为什么我的Python自定义math-overload类方法不起作用?

时间:2016-02-07 06:55:54

标签: python python-2.7 class math

最近,我在Python中使用了许多C算法原型。为了帮助我制作出最精确的模型,我尝试创建一个自定义数据类型,可用于将固定宽度整数(uint8_t和朋友)与标准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__期间__init__()和朋友的创建?

1 个答案:

答案 0 :(得分:2)

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