如何对int进行子类化并使其可变

3

能否对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是不可变的。

如果我像这样重新编写其中一个setter:

@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呢?

有什么疯狂的办法可以做到这一点吗?也许使用元类或其他什么东西?


我忘了提一个要求:

CustomBitVector的实例必须像int一样运作。特别地,我需要能够将它们传递给struct.pack函数。


你不能使整数本身可变(除非你用 C 写一个扩展),但你可以使用它而不是扩展它。 - Mad Physicist
3个回答

9
可以对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 互操作,比如不要试图让你的对象可用作 dict 的键。毕竟它们是可变的。
如果你真的很重视你的类是一个 int 子类,那么你必须放弃你想要的 c.sixth_property = True 语法。你需要选择一种替代方案,比如 c = c.with_sixth_property(True),并以非可变方式实现。

运行得非常好,而且最重要的是它可以与 struct.pack 一起使用。 - Stephen

1

我刚刚将我的概念验证代码打包并上传到PyPi,这是一个mutableint包。

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)

如何在调用__repr____str__时使用自定义函数创建MutableInt? - CS QGB

-1

这是我的解决方案。它还可以使整数可迭代。

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

这个程序会以各种方式崩溃。例如,当我测试时,x = MutableInt(0); x.set(1); print(x) 立即崩溃。 - user2357112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接