开发者

can't call __add__ through __getattr__( __getattribute__ )

It is object of the class A, in container's class tmpA. Not all method from A are in the tmpA. So for example: A + B is present , tmpA + B isn't present. I try to call method from A for tmpA. I can to call simple method, such as change(), but __add__ - don't work. If to remove inheritance from object, the code works.


#--------------------------------------
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
#---------------开发者_如何学C----------------------
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'"


Special methods are looked up on the class, that is, not on the instance of the class (except for some irregularities in old-style classes, which just mean a huge headache). So in particular the class's __getattr__ (for sane, new-style classes) is not getting called to look up __add__ when a + is performed - the metaclass's (type's, here) __getattr__ is.

"Removing inheritance from object" means popping right back into the hellzapoppin world of old-style classes and only stores up pain for the future: don't! Rather, if you have a class that must delegate some special methods, code them explicitly in the class (directly or via a class decorator), or make a custom metaclass that knows about this quirk (the metaclass's __getattr__, or other means, can then perform the task you crave).


I think X + Y is taken as X.__add__(Y).

So if you use

class tempA(A) then temp_a + b works because it inherits __add__ method and uses it like temp_a.__add__(b).

but if you use

class tempA(object) then it does not have __add__ method in class tempA to call when it encounters temp_a + b.


When you say tmp_a + b, Python looks in tmp_a.__class__.__dict__ and then object.__dict__ for the __add__ method (bypassing the hasattr/getattr type lookup)

Since it is not found anywhere, Python then looks to see if b has an __radd__ method that can handle tmp_a as the other parameter. Since it can't, the exception is thrown.

You will have to add a bunch of special methods to tmpA to get those to work properly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜