Reputation: 12202
I want to extract the - the name of the "current" methode - the class name of the current object/instance - the class name of the next base class of that object/instance
The problem in the example below is that the methode-name is not really that what I want. But I need to make that code reusable for a lot of classes. I don't want to multiply that code for each class I need it for.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, inspect
def notimpl_str(obj):
classname = obj.__class__.__name__
methode = sys._getframe().f_code.co_name
hi = inspect.getmro(obj.__class__)
nistr = 'In {}.{}()\nLook in {}.{}()' \
.format(classname,
methode,
hi[1].__name__,
methode)
return nistr
class Foo:
def test(self):
print(notimpl_str(self))
class Xoo(Foo):
def __init__(self):
self.test()
Xoo()
Background of my question:
I want to implement a generic not-implemented-error-message if someone would call Xoo().test()
. The message could like be
Please implement Xoo.test(). See the documentation of Foo.test() for more details.
Upvotes: 1
Views: 3100
Reputation: 12202
This is far away from perfect but a little bit more near to "generic". ;)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, inspect
def create_niestr(obj,
abstract_class,
methode):
classname = obj.__class__.__name__
hi = inspect.getmro(obj.__class__)
this_method = getattr(obj, methode)
base_method = getattr(abstract_class, methode)
if classname is not abstract_class.__name__ and this_method.__func__ is base_method:
nistr = 'Please implement {}.{}(). See the documentation of {}.{}() for more details.' \
.format(classname, methode, hi[1].__name__, methode)
else:
nistr = 'Normal execution.'
return nistr
class Foo:
def test(self):
nistr = create_niestr(self,
Foo,
sys._getframe().f_code.co_name)
print(nistr)
class Xoo(Foo):
pass
class Zoo(Foo):
def test(self):
super(self.__class__, self).test()
Foo().test()
Xoo().test()
Zoo().test()
Upvotes: 3
Reputation: 1909
Check this out!
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, inspect
class Foo:
def test(self):
classname = self.__class__.__name__
methode = sys._getframe().f_code.co_name
hi = inspect.getmro(self.__class__)
this_method = getattr(self, 'test')
base_method = getattr(Foo, 'test') #here 'Foo' is the base class and so this value has to be hard-coded for every base class inside which you paste this code
if classname is not "Foo" and this_method.__func__ is base_method:
nistr = 'Please implement {}.{}(). See the documentation of {}.{}() for more details.'\
.format(classname, methode, hi[1].__name__, methode)
print(nistr)
else:
print("Normal execution.") #put the actual code for the 'test' method here
class Xoo(Foo):
pass
class Zoo(Foo):
def test(self):
super(self.__class__, self).test()
Foo().test() #test has been defined so normal execution
Xoo().test() #test has not been defined so a message is shown
Zoo().test() #test has been defined, even if it is just for calling the base class's 'test' method, it is still a valid definition so normal execution
Output-
Normal execution.
Please implement Xoo.test(). See the documentation of Foo.test() for more details.
Normal execution.
About implementing a generic method as you have shown in the question, well, I would say that will create a lot of confusion and may not be even possible as the value of self cannot contain the calling object as well as the called object. Also, if your call another method for checking this, then sys._getframe().f_code.co_name
will no longer return the original method's name, which is what you want. So the best way would be to add this piece of code to every base class.
Upvotes: 1
Reputation: 1909
I think this is what you are looking for. I have added an additional parameter 'Inheritance hierarchy'.
import sys
import inspect
class Foo(object):
def __init__(self):
flag = 0
print("Subclasses:", end=" ")
for subclass in self.__class__.__subclasses__(): #prints the subclasses
print(subclass.__name__, end=" ")
flag = 1
if flag == 0:
print(None)
else:
print()
print("Class name: ", self.__class__.__name__) #prints the class name
print("Method name: ", sys._getframe().f_code.co_name) #prints the method name
a = inspect.getmro(self.__class__)
flag = 0
print("Inheritance Hierarchy:", end=" ")
for i in range(len(a)): #prints the inheritance hierarchy
if not i == 0:
print(a[(len(a)-1)-i].__name__, end=" ")
flag = 1
if flag == 0:
print(None)
else:
print("\n")
class Xoo(Foo):
def __init__(self):
flag = 0
print("Subclasses:", end=" ")
for subclass in self.__class__.__subclasses__(): #prints the subclasses
print(subclass.__name__, end=" ")
flag = 1
if flag == 0:
print(None)
else:
print()
print("Class name: ", self.__class__.__name__) #prints the class name
print("Method name: ", sys._getframe().f_code.co_name) #prints the method name
a = inspect.getmro(self.__class__)
flag = 0
print("Inheritance Hierarchy:", end=" ")
for i in range(len(a)): #prints the inheritance hierarchy
if not i == 0:
print(a[(len(a)-1)-i].__name__, end=" ")
flag = 1
if flag == 0:
print(None)
else:
print("\n")
class Zoo(Xoo):
def __init__(self):
flag = 0
print("Subclasses:", end=" ")
for subclass in self.__class__.__subclasses__(): #prints the subclasses
print(subclass.__name__, end=" ")
flag = 1
if flag == 0:
print(None)
else:
print()
print("Class name: ", self.__class__.__name__) #prints the class name
print("Method name: ", sys._getframe().f_code.co_name) #prints the method name
a = inspect.getmro(self.__class__)
flag = 0
print("Inheritance Hierarchy:", end=" ")
for i in range(len(a)): #prints the inheritance hierarchy
if not i == 0:
print(a[(len(a)-1)-i].__name__, end=" ")
flag = 1
if flag == 0:
print(None)
else:
pass
Foo()
Xoo()
Zoo()
Running the above code, you get the following output:
Subclasses: Xoo
Class name: Foo
Method name: __init__
Inheritance Hierarchy: Foo
Subclasses: Zoo
Class name: Xoo
Method name: __init__
Inheritance Hierarchy: Foo Xoo
Subclasses: None
Class name: Zoo
Method name: __init__
Inheritance Hierarchy: Foo Xoo Zoo
Upvotes: 1