7

我有一个样板类,它将一些操作委托给一个参考类。它看起来像这样:

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 元编程来使它更优雅和可读,但我不确定如何。

我听说过setattrgetattr,我想我可以做类似的事情

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 循环生成方法的基础知识,但是我不知道如何从其他地方调用这些方法。嘻嘻!

4

2 回答 2

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
于 2015-09-28T17:44:50.980 回答
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参数?)并将所有给它的参数传递给它的引用对象的方法argskwargs参数(见*args 和**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))
于 2015-09-28T17:27:58.147 回答