Let's say that I have a class defined in moduleA.py
which I want to add a method to, using some sort of loader method that takes a the name of a second module and the method defined there that should be bound
class ClassA(object):
def __init__(self,config):
super(ClassA, self).__init__()
self.a = 1
self.b = 2
self.meth1 = self. bind_method(config)
def bind_method(self,config):
# load method
<return method defined in config as a str 'moduleB.meth2'>
def calling_method():
return self.meth1()
where the method defined in moduleB.py
looks something like:
def meth2(self):
return self.a + self.b
The point being that I want to be able to write meth2
to be able to access class variables of ClassA
once it is bound. This way, when you would have something like:
from moduleA import ClassA
A = ClassA()
aout = A.calling_method()
Calling A.calling_method()
properly calls the method defined in moduleB.py
.
I've seen this sort of binding done in answers on SO after ClassA
is instantiated using types.MethodType
, but I haven't been able to dig up how to bind inside the class definition so that it is done internally when the class is instantiated.
Any suggestions on what should go in the bind_method
method would be much appreciated.
Python Code can be dynamically imported and classes can be dynamically created at run-time. Classes can be dynamically created using the type() function in Python. The type() function is used to return the type of the object. The above syntax returns the type of object.
The normal way to add functionality (methods) to a class in Python is to define functions in the class body. There are many other ways to accomplish this that can be useful in different situations. The method can also be defined outside the scope of the class.
Python isn't like Java or C# and you can just have functions that aren't part of any class. If you want to group together functions you can just put them together in the same module, and you can nest modules inside packages. Only use classes when you need to create a new data type, not just to group functions together.
import sys
import types
def getobj(astr):
"""
getobj('scipy.stats.stats') returns the associated module
getobj('scipy.stats.stats.chisquare') returns the associated function
"""
try:
return globals()[astr]
except KeyError:
try:
return __import__(astr, fromlist=[''])
except ImportError:
modname, _, basename = astr.rpartition('.')
if modname:
mod = getobj(modname)
return getattr(mod, basename)
else:
raise
class ClassA(object):
def __init__(self, methpath):
super(ClassA, self).__init__()
self.a = 1
self.b = 2
self.meth1 = types.MethodType(getobj(methpath), self)
a = ClassA('moduleB.meth2')
print(a.meth1())
# 3
Skipping the config stuff which wasn't clear to me, the binding itself would look like this:
from moduleB import meth2
ClassA.meth1 = meth2
The important part is that you're binding to the class, not to an instance. This way if you call meth1
on an instance, it will automatically receive the instance as the first argument.
Since meth2() is a function, it is a descriptor and you can bind it by calling the __get__() method.
def meth2(self):
return self.a + self.b
class ClassA(object):
def __init__(self,config):
super(ClassA, self).__init__()
self.a = 1
self.b = 2
self.meth1 = config.__get__(self, ClassA)
c = ClassA(meth2)
print c.meth1() #correctly prints 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With