setattr和getattr方法

时间:2015-09-28 17:07:13

标签: python metaprogramming dry getattr setattr

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

我听说过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循环生成方法,但后来我不知道如何从其他地方调用这些方法。 Heeeelp!

2 个答案:

答案 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参数?)并将所有给它的参数传递给引用对象的argskwargs参数的方法(有关这些参数的更多信息,请参阅*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))