Get __qualname__ of inherited function - python

class A:
def func(self):
print('This was in A')
class B(A):
def text(self):
print('This is in B')
print(B.func.__qualname__)
The output of this would be A.func but I'd like it to be B.func
It would be like functools.wraps but for class functions.

I'm not sure how exactly you'll be using this in logging, it would help if you could elaborate on your question. Here I assume what you want is a function (named print_func), that when passed with an instance method, prints the method name and class name of the actual instance.
In this case, you can just separately print the instance class name and the method name, for example:
class A:
def func(self):
print('This was in A')
class B(A):
def text(self):
print('This is in B')
def print_func(f):
print(f.__self__.__class__.__qualname__, ".", f.__name__)
b = B()
print_func(b.func) # B . func
The __self__ attribute of a bound instance method gives the instance that the method is bound to (in this case, b), and __class__ of an instance gives the class of the instance.
You can also extend the print_func method by checking whether f is a bound instance method, and add additional routines for normal functions, static methods, and class methods. An example would be:
import inspect
def print_func(f):
if inspect.ismethod(f):
# Could be instance method or class method.
self = f.__self__
if inspect.isclass(self):
print("classmethod", self.__qualname__ + "." + f.__name__)
else:
print(self.__class__.__qualname__ + "." + f.__name__)
else:
# The method is either an unbound instance method, a static method,
# or a normal function. Either case, it is not bound to an instance,
# so `__qualname__` should suffice.
# It would be non-trivial to print the actual class from which we
# accessed this function. See examples marked with asterisks (*) below.
print(f.__qualname__)
To see it in action:
class A:
def method(self): pass
#classmethod
def classmethod(cls): pass
#staticmethod
def staticmethod(): pass
class B(A):
pass
def function(): pass
a = A()
b = B()
print_func(A.method) # A.method
print_func(B.method) # A.method *
print_func(a.method) # A.method
print_func(b.method) # B.method
print_func(A.classmethod) # classmethod A.classmethod
print_func(B.classmethod) # classmethod B.classmethod
print_func(a.classmethod) # classmethod A.classmethod
print_func(b.classmethod) # classmethod B.classmethod
print_func(A.staticmethod) # A.staticmethod
print_func(B.staticmethod) # A.staticmethod *
print_func(function) # function

Seems that not so good solution, but it can help you:
class A:
def func(self):
print('This was in A')
class B(A):
def text(self):
print('This is in B')
def func(self):
return super().func()
print(B.func.__qualname__)

Related

How can I dynamically refer to a child class from the super class in Python?

Consider this situation:
class Foo(ABC):
#abstractmethod
def some_method(self):
return
class Bar(Foo):
def some_method(self, param):
# do stuff
return
class Baz(Foo):
def some_method(self, param):
# do stuff differently
return
def do_something_with_obj(some_obj: Foo):
some_param = 'stuff'
some_obj.some_method(some_param)
def main(cond):
if cond:
obj = Bar()
else:
obj = Baz()
do_something_with_obj(obj)
I get an Expected 0 positional arguments error when I try to call some_method() under the do_something_with_obj() method. Of course, this is because I'm essentially calling the abstract method. My question is, how can I dynamically refer to the child class method since I have to choose the right child class based on some condition beforehand?

Finding in which class or subclass methods were defined

After evaluating the following code:
class A():
def method1():
pass
def method2():
pass
class B(A):
def method3():
pass
def method4():
pass
class C(B):
def method1(): # notice the overriding of A.method1
pass
def method5():
pass
myC = C()
import inspect
# Find all methods
print [attr for attr in inspect.getmembers(myC) if callable(attr[1])]
[('method1', bound method C.method1 of <builtin.C instance at 0x079EA0D0>),
('method2', bound method C.method2 of <builtin.C instance at 0x079EA0D0>), ('method3', bound method C.method3 of <builtin.C instance at 0x079EA0D0>), ('method4', bound method C.method4 of <builtin.C instance at 0x079EA0D0), ('method5', builtin.C instance at 0x079EA0D0>)]
How to retrieve the origin of the methods ?
method1 and method5 come directly from class C definition
method3 and method4 come from subclass B of class C
method2 comes from subclass A of subclass B of class C.
For those who like to known the final goal, I want to display help for the methods directly defined in class C, not in subclasses.
You can check if the attribute is present in myC's class __dict__:
for attr in filter(lambda m: callable(m[1]), inspect.getmembers(myC)):
if attr[0] in myC.__class__.__dict__:
# print help
"""
method1 and method5 come directly from class C definition
method3 and method4 come from subclass B of class C
method2 comes from subclass A of subclass B of class C.
"""
import inspect
class A():
def method1():
pass
def method2():
pass
class D():
def method8():
pass
def method9():
pass
class B(A, D):
def method3():
pass
def method4():
pass
class C(B):
def method1(): # notice the overriding of A.method1
pass
def method5():
pass
# my solution is a recursive method for classes/methods(nested)
def bases(cls):
for _bases in cls.__bases__:
print cls, ">", _bases
if inspect.isclass(_bases):
print ">", _bases, [method for method in dir(_bases) if callable(getattr(_bases, method))]
bases(_bases)
bases(C)
__builtin__.C > __builtin__.B
> __builtin__.B ['method1', 'method2', 'method3', 'method4', 'method8', 'method9']
__builtin__.B > __builtin__.A
> __builtin__.A ['method1', 'method2']
__builtin__.B > __builtin__.D
> __builtin__.D ['method8', 'method9']

Get caller class instance (object) inside method that was called?

Let say I have
class A(object):
def m1(self):
B().m2()
class B(object):
def m2(self):
#return object of caller instance
#let say 'a' is instance object this method was called from
return a
a = A().m1()
You can pass the caller instance, and make it a parameter of the called function itself. Something like -
class A(object):
def m1(self):
B().m2(self)
class B(object):
def m2(self, obj):
#return object of caller instance
#let say 'a' is instance object this method was called from
return obj
a = A().m1()

Refer to own class in a static method

Is there a shorthand for referring to its own class in a static method?
Say I have this piece of code:
class SuperLongClassName(object):
#staticmethod
def sayHi():
print 'Hi'
#staticmethod
def speak():
SuperLongClassName.sayHi() # Is there a shorthand?
Yes, use #classmethod instead of #staticmethod. The whole point of #staticmethod is to remove the extra class parameter if you don't need it.
class SuperLongClassName(object):
#classmethod
def sayHi(cls):
print 'Hi'
#classmethod
def speak(cls):
cls.sayHi()
You probably want a classmethod. It works like a staticmethod, but takes the class as an implicit first argument.
class Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass(object):
#classmethod
def foo(cls):
print cls.__name__
Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass.foo() # prints Claaa...
Warning:
class Subclaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass(
Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass):
pass
Subclaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass.foo() # prints Subclaaa...
Alternatively, define a shorter alias for your class at module level:
class Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2(object):
#staticmethod
def foo():
return _cls2
_cls2 = Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2
# prints True
print (Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2 is
Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2.foo())

How can I tell what class in the polymorphic hierarchy contains the method I'm about to call?

If I have:
class A():
def f(self):
print("running function, f from class A")
class B(A):
def __init__(self):
A.__init__(self)
def f(self):
print("running function, f from class B")
and I make an instance of class B and call f on it, we all know we'll see the message about "from class B." But is there a way for me to inspect my object and make sure my sub-class has overridden my method? Something like:
obj = B()
assert(not obj.f.livesIn(A))
class A():
def f(self):
print("running function, f from class A")
class B(A):
def f(self):
print("running function, f from class B")
class C(A):
pass
This shows that B.f does not equal A.f. So B must override f:
obj = B()
print(obj.__class__.f == A.f)
# False
This shows that C.f equals A.f. So C must not have overridden f:
obj = C()
print(obj.__class__.f == A.f)
# True
If you want to force the child class to override, you can raise NotImplementedError().
Doing the inspection is possible too... And I see unutbu just posted an example, so I won't repeat it. :)

Categories

Resources