Динамически привязывать метод к экземпляру класса в python
Допустим, у меня есть класс, определенный в moduleA.py
к которому я хочу добавить метод, используя некоторый метод загрузчика, который принимает имя второго модуля и метод, определенный там, который должен быть связан
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()
где метод определен в moduleB.py
выглядит примерно так:
def meth2(self):
return self.a + self.b
Дело в том, что я хочу иметь возможность писать meth2
чтобы иметь возможность доступа к переменным класса ClassA
как только это связано. Таким образом, когда у вас будет что-то вроде:
from moduleA import ClassA
A = ClassA()
aout = A.calling_method()
призвание A.calling_method()
правильно вызывает метод, определенный в moduleB.py
,
Я видел такую привязку в ответах на SO после ClassA
создается с использованием types.MethodType
, но я не смог выяснить, как связать внутри определения класса, чтобы это было сделано внутри, когда создается экземпляр класса.
Любые предложения о том, что должно идти в bind_method
метод будет высоко ценится.
4 ответа
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
Пропуская вещи конфигурации, которые мне не ясны, сама привязка будет выглядеть так:
from moduleB import meth2
ClassA.meth1 = meth2
Важной частью является то, что вы привязываетесь к классу, а не к экземпляру. Таким образом, если вы звоните meth1
на экземпляре он автоматически получит экземпляр в качестве первого аргумента.
Поскольку meth2() - это функция, это дескриптор, и вы можете связать ее, вызвав метод __get__().
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
На самом деле есть гораздо более простой способ сделать это:
class ClassA(object):
def __init__(self,config):
super(ClassA, self).__init__()
self.a = 1
self.b = 2
from moduleB import meth2 as meth1
def calling_method():
return self.meth1()