How to subclass int and make it mutable

时光总嘲笑我的痴心妄想 提交于 2019-12-10 12:06:19

问题


Is it possible to subclass int and make it mutable?

Consider the following class:

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

I trying to make a nice interface to a bit vector. I'm reading a proprietary protocol off of a socket and I've made classes to represent the messages I'm sending/receiving. Often these messages include bit vectors and it would be nice to deal with them like this.

This already works great for reading the bit vector values, but setting them doesn't work because int is immutable.

If I rewrite one of the setters like:

@sixth_property.setter
def sixth_property(self, val):
    print 'before:', self
    self |= bool(val) << 6
    print 'after:', self

Then I get this behavior:

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

I can see my folly ... I'm assigning to self instead of modifying it. How can I modify self in this case?

Any crazy hack to make this happen? Maybe using a metaclass or something?


UPDATE

I forgot to mention a requirement:

Instances of CustomBitVector must behave like int. In particular, I need to be able to pass them to struct.pack


回答1:


Is it possible to subclass int and make it mutable?

Sort of. You can add all the mutable parts you want, but you can't touch the int parts, so the degree of mutability you can add won't help you.

Instead, don't use an int subclass. Use a regular object that stores an int. If you want to be able to pass it to struct.pack like an int, implement an __index__ method to define how to interpret your object as an int:

class IntLike(object): # not IntLike(int):
    def __init__(self, value=0):
        self.value = value
    def __index__(self):
        return self.value
    ...

You can implement additional methods like __or__ for | and __ior__ for in-place, mutative |=. Don't try to push too hard for complete interoperability with ints, though; for example, don't try to make your objects usable as dict keys. They're mutable, after all.

If it's really important to you that your class is an int subclass, you're going to have to sacrifice the c.sixth_property = True syntax you want. You'll have to pick an alternative like c = c.with_sixth_property(True), and implement things non-mutatively.




回答2:


Here is my solution. It also make an integer iteratable too.

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



回答3:


I just package up my proof-of-concept code and upload a mutableint package to PyPi.

https://pypi.org/project/mutableint/

Here is the usage.

from mutableint import MutableInt

# create a mutable integer with value 10 
a = MutableInt(10)

# change the value of a to 11
a.set(11)


来源:https://stackoverflow.com/questions/44935204/how-to-subclass-int-and-make-it-mutable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!