是否可以继承int
并使其可变?
考虑以下课程:
class CustomBitVector(int):
# bit 7
@property
def seventh_property(self):
return bool(self & (1 << 7))
@seventh_property.setter
def seventh_property(self, val):
self |= bool(val) << 7
# bit 6
@property
def sixth_property(self):
return bool(self & (1 << 6))
@sixth_property.setter
def sixth_property(self, val):
self |= bool(val) << 6
# ... a few more of these ...
# bit 0
@property
def zeroth_property(self):
return bool(self & (1 << 0))
@zeroth_property.setter
def zeroth_property(self, val):
self |= bool(val) << 0
我试图为一个位向量创建一个很好的接口。我正在从套接字读取专有协议,并且我已经创建了类来表示我发送/接收的消息。通常这些消息包括位向量,这样处理它们会很好。
这对于读取位向量值非常有用,但设置它们并不起作用,因为int
是不可变的。
如果我改写其中一个设置者:
@sixth_property.setter
def sixth_property(self, val):
print 'before:', self
self |= bool(val) << 6
print 'after:', self
然后我得到这种行为:
In [2]: c = CustomBitVector()
In [3]: c.sixth_property
Out[3]: False
In [4]: c.sixth_property = True
before: 0
after: 64
In [5]: c
Out[5]: 0
In [6]: c.sixth_property
Out[6]: False
我可以看到我的愚蠢......我指定self
而不是修改它。在这种情况下如何修改self
?
任何疯狂的黑客都能实现这一目标?也许使用元类或其他东西?
UPDATE我忘了提一个要求:
CustomBitVector
的实例必须表现得像int
。特别是,我需要能够将它们传递给struct.pack
答案 0 :(得分:4)
是否可以将int子类化并使其可变?
排序。你可以添加你想要的所有可变部分,但你不能触及int部分,所以你可以添加的可变性程度对你没有帮助。
相反,不要使用int子类。使用存储int的常规对象。如果您希望能够像int一样将它传递给struct.pack
,请实现__index__
方法来定义如何将对象解释为int:
class IntLike(object): # not IntLike(int):
def __init__(self, value=0):
self.value = value
def __index__(self):
return self.value
...
您可以为__or__
和|
实施其他方法,例如__ior__
和|=
,用于就地变更int
。但是,不要试图过分努力以实现与int的完全互操作性;例如,不要试图使您的对象可用作dict键。毕竟,它们是可变的。
如果您的类是c.sixth_property = True
子类对您来说非常重要,那么您将不得不牺牲所需的c = c.with_sixth_property(True)
语法。您必须选择./folder_name
之类的替代方案,并以非变异的方式实施。
答案 1 :(得分:0)
这是我的解决方案。它还使整数也可以迭代。
import ctypes
class MutableInt(int):
def __init__(self, val = 0):
self._val = val
def __int__(self):
return self._val
def __index__(self):
return self._val
def __str__(self):
return str(self._val)
def __repr__(self):
return repr(self._val)
def __iter__(self):
self._iter_cnt = 0
return self
def __next__(self):
if self._iter_cnt == 0:
self._iter_cnt = 1
return self._val
else:
raise StopIteration
def set(self, val):
self._val = val
ob_digit = ctypes.c_long.from_address(id(self)+24)
ob_digit.value = val
答案 2 :(得分:0)
我只打包了概念验证代码,然后将mutableint包上传到PyPi。
https://pypi.org/project/mutableint/
这里是用法。
from mutableint import MutableInt
# create a mutable integer with value 10
a = MutableInt(10)
# change the value of a to 11
a.set(11)