views:

86

answers:

2
class A:
    def x ( self ):
        print( self.__class__ )

class B ( A ):
    pass

b = B()
b.x()

In the above situation, is there any way for the method x to get a reference to class A instead of B? Of course simply writing print( A ) is not allowed, as I want to add some functionality with a decorator that needs the class A (and as I can't pass A itself to the decorator directly, as the class doesn't exist yet at that point).

+2  A: 

Unless you have super-calls involved (or more generally subclasses that override x and call directly to A.x(self) as part of their override's implementation), looking for the first item in type(self).mro() that has an x attribute would work --

next(c for c in type(self).mro() if hasattr(c, 'x'))

If you do need to cover for super-calls, it's harder -- unless you happen to know that no super-class of A defines an x attribute (and of course it's easier to know about your superclasses than your subclasses, though multiple inheritance does complicate it;-) in which case you only need the last appropriate item of the mro instead of the first one.

Alex Martelli
While this wasn't really what I needed, it gave me the needed hint to solve my problem, thanks :)
poke
+2  A: 

You can use name mangling to associate the class a method is defined in with a method:

def set_defining_class(cls):
    setattr(cls, '_%s__defining_class' % (cls.__name__,), cls)
    return cls

@set_defining_class
class A(object):
    def x (self):
        print(self.__defining_class)

@set_defining_class
class B ( A ):
    pass


b = B()
b.x()

Done here with a class decorator, but you could do it by hand, or in a metaclass too.

Matt Anderson
That's actually a nice way of storing such information, thanks!
poke