在Python中模拟指针进行算术运算
这个问题在
上提到,询问如何在Python中模拟指针,解决方案中有一个不错的建议,就是可以这样做:
class ref:
def __init__(self, obj): self.obj = obj
def get(self): return self.obj
def set(self, obj): self.obj = obj
然后可以用来做,比如:
a = ref(1.22)
b = ref(a)
print a # prints 1.22
print b.get() # prints 1.22
这个类可以进行修改,以避免在打印语句中使用 get
,可以通过添加:
def __str__(self): return self.obj.__str__()
然后,
print b # prints out 1.22
现在我希望能够像对待 a
一样对待 b
进行算术运算,我想这相当于说我希望 a
和 b
的行为和 obj
完全一样。有没有办法做到这一点?我尝试添加一些方法,比如:
def __getattribute__(self, attribute): return self.obj.__getattribute__(attribute)
def __call__(self): return self.obj.__call__()
但是无论如何,
print a + b
的输出总是
Traceback (most recent call last):
File "test.py", line 13, in <module>
print a + b
TypeError: unsupported operand type(s) for +: 'instance' and 'instance'
有没有人有什么想法,如何修改 ref
类以实现这个功能?
感谢任何建议!
2 个回答
这里有两个可能的问题。
首先,你似乎依赖于你的 __getattribute__
实现来让解释器找到正确的 __add__
方法。不幸的是,我发现 Python 解释器在找到一些特殊函数时常常会遇到麻烦,比如 __add__
或 __call__
,尤其是当这些函数是动态创建的(也就是说,在定义类的时候并没有明确地把它们放进类里)。手册中明确提到这一点,至少对于新式类来说:
对于新式类,特殊方法的隐式调用只有在定义在对象的类型上时才能保证正确工作,而不是在对象的实例字典中。
虽然我觉得即使在旧式类中,我也遇到过类似的问题。
第二,仅仅重定向 __add__
是不够的。即使解释器成功地将
a + b
简化为
float.__add__( 1.22, b )
浮点类仍然不知道如何将一个 float
加到一个 ref
上。所以你的 __add__
方法必须明确地解引用目标(如果是间接引用,还得继续解引用...)。像这样:
class ref:
def __init__(self, obj):
self.obj = obj
def get(self): return self.obj
def set(self, obj): self.obj = obj
def __str__(self): return self.obj.__str__()
def __add__( self, other ):
while isinstance( other, ref ):
other = other.obj
return self.obj.__add__( other )
a = ref(1.22)
b = ref(a)
print a
print b
print a + b
在 __add__
中的 while
循环确保你已经将所有嵌套的引用解包到基础对象。
如果我是这样做的,并且我使用过类似的结构来实现代理模式,我会重构代码,把 while
循环放到一个单独的方法中,比如叫 getBaseObject()
,然后在每次需要链条底部的实际对象时调用这个方法。
在编程中,+
这个加法符号是通过左边的对象里的__add__()
方法来实现的,或者是通过右边的对象里的__radd__()
方法来实现的。
点击这里了解更多。