最近,我在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__()
和朋友的创建?
答案 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