views:

113

answers:

2

I'm trying to call a method of the superclass by using a variable method name. Normally, I would see the following two lines of code as equivalent:

someObj.method()
someObj.__getattribute__( 'method' )()

And in fact I believe, this is also what actually happens when I use the first line. However, in the following example, the second line produces a weird problem.

I use super to construct a super object and call the method of the super class. Doing it directly works as expected, but using __getattribute__ to get the method first, results in a indefinite loop which calls the method of the subclass again and again.

See the following code:

class A:
    def example ( self ):
        print( 'example in A' )

class B ( A ):
    def example ( self ):
        print( super( B, self ).example )
        print( super( B, self ).__getattribute__( 'example' ) )
        super( B, self ).example()
        #super( B, self ).__getattribute__( 'example' )()

        print( 'example in B' )

x = B()
x.example()

If you run that code, everything works as expected, and you should get an output similar to this:

<bound method B.example of <__main__.B object at 0x01CF6C90>>
<bound method B.example of <__main__.B object at 0x01CF6C90>>
example in A
example in B

So both methods, the one with the direct access and the one via __getattribute__, look identical. If you however replace the method call by the commented-out line, you'll end up with a recursion runtime error.

Why does this happen, and more importantly, how can I actually access the method in the same way as python internally does, when I use the working line?

edit

When I thought I already tried everything, I found this to be working:

super.__getattribute__( super( B, self ), 'example' )()

It actually equals to super( B, self ).example.

A: 

Getting the example attribute of a B object results in a bound copy of B.example. Calling this will result in a recursion error. That you call A.__getattribute__() is irrelevant; you still have a B object.

Ignacio Vazquez-Abrams
+3  A: 

Don't use __getattribute__ for this: it does not do what you think it does. (It is a specialized part of Python's machinery, mainly for use if you're implementing new attribute access magic.)

For normal attribute access, use the getattr / setattr / delattr builtins:

self.example           == getattr(self, 'example')
super(B, self).example == getattr(super(B, self), 'example')

(If you want to understand what __getattribute__ does, read the Descriptor HowTo Guide and Python Data model reference.)

Piet Delport