Ste*_*hen 1 python subclass immutability
是否可以子类化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
Run Code Online (Sandbox Code Playgroud)
我试图为位向量制作一个很好的界面。我正在从套接字读取专有协议,并且我已经创建了类来表示我正在发送/接收的消息。通常这些消息包括位向量,像这样处理它们会很好。
这对于读取位向量值已经很有效,但是设置它们不起作用,因为它int是不可变的。
如果我重写其中一个设置器,例如:
@sixth_property.setter
def sixth_property(self, val):
print 'before:', self
self |= bool(val) << 6
print 'after:', self
Run Code Online (Sandbox Code Playgroud)
然后我得到这种行为:
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
Run Code Online (Sandbox Code Playgroud)
我可以看到我的愚蠢......我正在分配self而不是修改它。self在这种情况下我该如何修改?
任何疯狂的黑客来实现这一目标?也许使用元类或其他什么?
我忘了提一个要求:
的实例CustomBitVector必须表现得像int. 特别是,我需要能够将它们传递给struct.pack
是否可以将 int 子类化并使其可变?
有点。你可以添加你想要的所有可变部分,但你不能触及 int 部分,所以你可以添加的可变程度对你没有帮助。
相反,不要使用 int 子类。使用存储 int 的常规对象。如果您希望能够struct.pack像 int 一样传递它,请实现一个__index__方法来定义如何将您的对象解释为 int:
class IntLike(object): # not IntLike(int):
def __init__(self, value=0):
self.value = value
def __index__(self):
return self.value
...
Run Code Online (Sandbox Code Playgroud)
您可以实现其他方法,例如__or__for|和__ior__for in-place mutative |=。不过,不要试图过分追求与整数的完全互操作性;例如,不要试图使您的对象可用作字典键。毕竟,它们是可变的。
如果你的类是一个int子类对你来说真的很重要,你将不得不牺牲c.sixth_property = True你想要的语法。您必须选择一个替代方案,例如c = c.with_sixth_property(True),并以非可变方式实施。