python - 为什么我的 Python 自定义数学重载类方法不起作用?

标签 python python-2.7 class math

最近,我一直在用 Python 制作很多 C 算法的原型(prototype)。为了帮助我制作最准确的模型,我尝试创建一个自定义数据类型,可用于将固定宽度整数(uint8_t 和 friend )与标准 Python 数学无缝混合。

为此,我编写了一个小自定义类,它提供模包装的数学和逻辑函数(以确保在 255 上添加“1”将在 8 位变量上返回 0 值)。

一切似乎都很顺利,除了我的自定义数学函数似乎没有被解释器调用! 使用下面的代码:

class MockUint(object):
    @staticmethod
    def __math__(op1, op2, name, width = 128):
        if type(op1) is MockUint:
            width = op1._width
            op1 = int(op1)

        if type(op2) is MockUint:
            width = op2._width if (op2._width > width) else width
            op2 = int(op2)

        mask = 2**width - 1
        result = int.__dict__[name](op1, op2) & mask
        return MockUint(result, width)

    def __init__(self, value=0, width=64):
        self._width = width
        self._value = value

        math_funcs = ['__add__', '__sub__', '__mul__', '__floordiv__',
                      '__mod__', '__divmod__', '__pow__', '__lshift__',
                      '__rshift__', '__and__', '__xor__', '__or__']

        for func in math_funcs:
            setattr(self, func, lambda x, y: self.__math__(x, y, func))

    def __repr__(self):
        return "%d" % self._value

    def __int__(self):
        return self._value

我得到以下结果:

> test = MockUint(0, 8)
> test + 4
TypeError: unsupported operand type(s) for +: 'MockUint' and 'int'

如果我使用类似模式手动声明所有函数,

def __add__(self, op):
    return self.__math__(self, op, '__add__')

一切似乎都按如下所示进行:

> test = MockUint(0, 8)
> test + 4
4

如果可以避免的话,我真的不想用 12 个相同的方法使代码变得困惑。如何让解释器正确检测到 __add__ 和 friend 是在 __init__() 期间创建的?

最佳答案

official documentation 中所述魔术方法必须在类上定义,而不是在实例上。

您有两种选择来解决您的问题:

<强>1。使用旧式类

在旧式类中(我不建议使用它们),您可以在实例上定义魔术方法,它们将起作用。您只需更改 lambda 函数,因为它们仅传递一个参数(此处隐含了 self)

class Int:
    def __init__(self):
        self.value = ...
        setattr(self, "__add__", lambda other: self.value + other)

<强>2。定义类的方法

class Int(object):
    def __init__(self):
        self.value = ...

    @classmethod
    def static_init(cls):
        setattr(cls, "__add__", lambda self, other: self.value + other)

Int.static_init()

为了避免额外调用 static_init,您可以创建一个元类并在其 __init__() 中添加魔术方法

2b。与元类

class IntMeta(type):
    def __init__(cls, *args):
        setattr(cls, "__add__", lambda self, other: self.value + other)

class Int(object):
    __metaclass__ = IntMeta
    def __init__(self, value):
        self.value = value

关于python - 为什么我的 Python 自定义数学重载类方法不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35250663/

相关文章:

python - 将两个列表与列表或无值合并的有效方法

javascript - 访问类中的构造函数属性

objective-c - 错误: unrecognized selector sent to class

python - 从字典创建数据框 - python

python - 在 Python 中使用的高级邮件

python - 将子流程作为字符串重定向到变量

python - 向客户端流式传输数据

java - 有没有办法找到一个字段是否是与 isPrimitive() 相同的 boolean 值?

python - 如何子类化 numpy .`ma.core.masked_array` ?

python - 将 factory_boy 与 SQLAlchemy 和类方法一起使用