最近,我一直在用 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/