无法通过 __getattr__( __getattribute__ ) 调用 __add__
这是一个类A的对象,放在一个叫tmpA的容器类里。并不是类A里的所有方法都在tmpA里。例如:A + B这个方法在这里是可以用的,但tmpA + B这个方法就不行。我尝试在tmpA里调用类A的方法。我可以调用一些简单的方法,比如change(),但是__add__
这个方法就不行。如果把对象的继承去掉,代码就能正常工作了。
#--------------------------------------
class A(object):
def __init__( self, x, y ):
self.x = x
self.y = y
pass
#-------
def __add__( self, arg ):
tmp1 = self.x + arg.x
tmp2 = self.y + arg.y
return tmpA( A( tmp1, tmp2 ) )
def change( self, x, y ):
self.x = x
self.y = y
pass
pass
#------------------------------------------
class tmpA( object ):
def __init__( self, theA ):
self.A = theA
pass
#-------
def _print ( self ):
print " x =", self.A.x
print " y =", self.A.y
pass
#-------
def __call__( self ):
return self.A
#-------
def __coerce__( self, *args ):
return None
#-------
def __getattr__( self, *args ):
name = args[ 0 ]
try:
attr = None
exec "attr = self.__call__().%s" % name
return attr
except :
raise AttributeError
#--------------------------------------
class B( object ):
def __init__( self, x, y):
self.x = x
self.y = y
pass
#-------------------------------------
a=A( 1,2 );
b=B( 3,4 );
tmp_a = a + b;
tmp_a.change( 0, 0 ) # very well
v = tmp_a + b #TypeError: "unsupported operand type(s) for +: 'tmpA' and 'B'"
3 个回答
当你写 tmp_a + b
这个表达式时,Python 会先去查找 tmp_a.__class__.__dict__
和 object.__dict__
中是否有 __add__
这个方法(这个过程会跳过一些常规的查找方式)。
如果找不到这个方法,Python 接着会检查 b
是否有一个叫 __radd__
的方法,看看它能否处理 tmp_a
作为另一个参数。如果也找不到,程序就会报错。
为了让这些操作正常工作,你需要在 tmpA
中添加一些特殊的方法。
我觉得 X + Y
其实是被当作 X.__add__(Y)
来处理的。
所以如果你使用
class tempA(A)
,那么 temp_a + b
就能正常工作,因为它继承了 __add__
方法,并且像 temp_a.__add__(b)
这样使用它。
但是如果你使用
class tempA(object)
,那么在 class tempA
中就没有 __add__
方法可以调用,当它遇到 temp_a + b
的时候就会出问题。
特殊方法是通过类来查找的,也就是说,它们不是通过类的实例来查找的(除了旧式类的一些不规则情况,这会让人很头疼)。所以,特别是对于正常的新式类来说,当你使用+
进行加法运算时,类的__getattr__
方法不会被调用来查找__add__
,而是会调用元类(这里是type
)的__getattr__
方法。
“从object
中移除继承”意味着你又回到了旧式类的混乱世界,这只会给未来带来麻烦:不要这样做!相反,如果你有一个类需要处理一些特殊方法,最好在类中明确地编写这些方法(可以直接写在类里,或者通过类装饰器),或者创建一个自定义的元类,让它知道这个特殊情况(元类的__getattr__
或其他方法可以完成你想要的任务)。