我有一个boiler platey类,它将一些操作委托给引用类。它看起来像这样:
class MyClass():
def __init__(self, someClass):
self.refClass = someClass
def action1(self):
self.refClass.action1()
def action2(self):
self.refClass.action2()
def action3(self):
self.refClass.action3()
这是refClass:
class RefClass():
def __init__(self):
self.myClass = MyClass(self)
def action1(self):
#Stuff to execute action1
def action2(self):
#Stuff to execute action2
def action3(self):
#Stuff to execute action3
我想使用Python元编程来使这更优雅和可读,但我不确定如何。
class MyClass():
def __init__(self, someClass):
self.refClass = someClass
for action in ['action1', 'action2', 'action3']:
def _delegate(self):
getattr(self.refClass, action)()
然后我知道我需要从某个地方做这个,我猜:
MyClass.setattr(action, delegate)
我无法完全掌握这个概念。我理解不重复代码的基础知识,并使用带有函数式编程的for循环生成方法,但后来我不知道如何从其他地方调用这些方法。 Heeeelp!
答案 0 :(得分:8)
Python已经包含对包含类的通用委托的支持。只需将MyClass
的定义更改为:
class MyClass:
def __init__(self, someClass):
self.refClass = someClass # Note: You call this someClass, but it's actually some object, not some class in your example
def __getattr__(self, name):
return getattr(self.refClass, name)
定义时,只要在实例本身找不到属性,就会在具有被访问属性名称的实例上调用__getattr__
。然后,通过调用getattr
来委托包含的对象,以查找包含对象的属性并将其返回。这样每次进行动态查找会花费很少,所以如果你想避免它,你可以在__getattr__
第一次请求时懒惰地缓存属性,这样后续访问就是直接的:
def __getattr__(self, name):
attr = getattr(self.refClass, name)
setattr(self, name, attr)
return attr
答案 1 :(得分:2)
就个人而言,为了委派事情,我通常会这样做:
def delegate(prop_name, meth_name):
def proxy(self, *args, **kwargs):
prop = getattr(self, prop_name)
meth = getattr(prop, meth_name)
return meth(*args, **kwargs)
return proxy
class MyClass(object):
def __init__(self, someClass):
self.refClass = someClass
action1 = delegate('refClass', 'action1')
action2 = delegate('refClass', 'action2')
这将创建您需要的所有委托方法:)
对于某些解释,这里的委托功能只是创建一个"代理"函数将作为一个类方法(参见self
参数?)并将所有给它的参数传递给引用对象的args
和kwargs
参数的方法(有关这些参数的更多信息,请参阅*args and **kwargs?)
您也可以使用列表创建此列表,但我更喜欢第一个,因为它对我来说更明确:)
class MyClass(object):
delegated_methods = ['action1', 'action2']
def __init__(self, someClass):
self.refClass = someClass
for meth_name in self.delegated_methods:
setattr(self, meth_name, delegate('refClass', meth_name))