如何子类化 int 并使其可变

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

use*_*ica 7

是否可以将 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),并以非可变方式实施。