2017-01-07 1 views
7

У меня есть значение, которое обычно используется во всем моем коде в разных единицах. Например. представляющий размер буфера в количестве BYTES, но во многих местах, ссылающихся на размер как KB или как MB (это всего лишь пример, а не мой реальный прецедент).Добавление свойства в значение int в python

Для элегантности и простоты использования я хочу избежать явных преобразований (например, size/1024, или b_to_mb(size)), потому что они необходимы во многих разных местах.

Я думал, что могу достичь этого со свойствами, что упрощает преобразование (x.kb или x.mb), а также заставляет вызывающего абонента не знать о единицах сохраненного фактического значения.

Мой код выглядит следующим образом:

class BufferSize(int): 
    @property 
    def b(self): 
     return int(self) 
    @property 
    def kb(self): 
     return self.b/1024 
    @property 
    def mb(self): 
     return self.kb/1024 

Это работает, пока я не использовать арифметические операторы:

s = BufferSize(500000) 
s.kb 
=> 488.28125 # ok 
s.mb 
=> 0.476837158203125 # ok 
type(s + BufferSize(0)) 
=> int # type lost... 

Есть ли способ, чтобы обеспечить арифметические операции сохраняют тип? То есть, кроме переопределения каждого из них?

Или, может быть, другой и лучший способ решить первоначальную проблему?

+0

Я бы рекомендовал обертывания Int вместо унаследованного от междунар, так что вы случайно не добавить BufferSize в количестве килобайт или что-то. Что касается арифметических операторов, вы должны определить их индивидуально. Это не так много значимых; вам не нужно определять все из них. – user2357112

+3

См. [Pint] (https://pint.readthedocs.io/en/0.7.2/) для манипуляций с общими единицами. –

+1

@PeterWood Pint - абсолютно правильный инструмент для решения этой проблемы. Благодарю. – shx2

ответ

2

Ну, это не так много повторно реализовать в обертке/отбрасываемой результаты магических методов int «s, по крайней мере, те, которые возвращают int сек .. Все, из них, к сожалению. Интересно, не можете ли вы использовать декоратор или метакласс, чтобы ускорить это.

class BufferSize(int): 
    @property 
    def b(self): 
     return int(self) 
    @property 
    def kb(self): 
     return self.b/1024 
    @property 
    def mb(self): 
     return self.kb/1024 

    def __add__(self, *args, **kwds): 
     return BufferSize(super(BufferSize, self).__add__(*args, **kwds)) 

v = BufferSize(1) + BufferSize(2) 

print v, type(v) 

выход:

3 <class '__main__.BufferSize'> 

Я также думал о добавлении непосредственно свойство Int себя, но быстрый тест исключено, что из.

>>> int.b = "b" 

выход:

can't set attributes of built-in/extension type 'int'