Reputation: 8391
I have two classes:
class A:
def foo(self):
print(<get the defining class>)
class B(A):
pass
Now, I need to replace <get the defining class>
by a code such that this:
a = A()
b = B()
a.foo()
b.foo()
produces this (i.e. this is the expected behaviour):
A
A
I tried self.__class__.__name__
but that obviously produces B
for the last call as the self
is, in fact, of class B
.
So the ultimate question is: if I'm in a method body (which is not a class method), how can I get the name of the class the method is defined in?
Upvotes: 0
Views: 61
Reputation: 1872
I'm assuming that you don't want to hard-code this logic into each function, since you could do so trivially in your example code.
If the print
statement is always the first statement of the methods for which you want this behaviour, one possible solution would be to use a decorator.
def print_defining_class(fn):
calling_class = fn.__qualname__.split('.')[0]
def decorated(*args, **kwargs):
print(calling_class)
return fn(*args, **kwargs)
return decorated
class A:
@print_defining_class
def method(self): pass
class B(A): pass
A().method() # A
B().method() # A
Upvotes: -1
Reputation: 160377
The simplest way to do this is by using the functions qualified name:
class A:
def foo(self):
print(self.foo.__qualname__[0])
class B(A):
pass
The qualified name consists of the class defined and the function name in cls_name.func_name
form. __qualname__[0]
suits you here because the class name consists of a single character; it's better of course to split on the dot and return the first element self.foo.__qualname__.split('.')[0]
.
For both, the result is:
>>> a = A()
>>> b = B()
>>> a.foo()
A
>>> b.foo()
A
A more robust approach is climbing the __mro__
and looking inside the __dict__
s of every class for a function type(self).foo
:
def foo(self):
c = [cls.__name__ for cls in type(self).__mro__ if getattr(type(self), 'foo', None) in cls.__dict__.values()]
print(c[0])
This is a bit more complex but yields the same result.
Upvotes: 2