无法通过 __getattr__( __getattribute__ ) 调用 __add__

2 投票
3 回答
666 浏览
提问于 2025-04-15 20:02

这是一个类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 个回答

1

当你写 tmp_a + b 这个表达式时,Python 会先去查找 tmp_a.__class__.__dict__object.__dict__ 中是否有 __add__ 这个方法(这个过程会跳过一些常规的查找方式)。

如果找不到这个方法,Python 接着会检查 b 是否有一个叫 __radd__ 的方法,看看它能否处理 tmp_a 作为另一个参数。如果也找不到,程序就会报错。

为了让这些操作正常工作,你需要在 tmpA 中添加一些特殊的方法。

2

我觉得 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 的时候就会出问题。

7

特殊方法是通过来查找的,也就是说,它们不是通过类的实例来查找的(除了旧式类的一些不规则情况,这会让人很头疼)。所以,特别是对于正常的新式类来说,当你使用+进行加法运算时,类的__getattr__方法不会被调用来查找__add__,而是会调用元类(这里是type)的__getattr__方法。

“从object中移除继承”意味着你又回到了旧式类的混乱世界,这只会给未来带来麻烦:不要这样做!相反,如果你有一个类需要处理一些特殊方法,最好在类中明确地编写这些方法(可以直接写在类里,或者通过类装饰器),或者创建一个自定义的元类,让它知道这个特殊情况(元类的__getattr__或其他方法可以完成你想要的任务)。

撰写回答