setattr和getattr方法

zap*_*lla 5 python metaprogramming dry setattr getattr

我有一个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()
Run Code Online (Sandbox Code Playgroud)

这是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
Run Code Online (Sandbox Code Playgroud)

我想使用Python Metaprogramming使这更优雅和可读,但我不知道如何.

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

class MyClass():

    def __init__(self, someClass):            
        self.refClass = someClass

    for action in ['action1', 'action2', 'action3']:
        def _delegate(self):
            getattr(self.refClass, action)()
Run Code Online (Sandbox Code Playgroud)

然后我知道我需要从某个地方做这个,我想:

MyClass.setattr(action, delegate)
Run Code Online (Sandbox Code Playgroud)

我无法完全掌握这个概念.我理解不重复代码的基础知识,并使用带有函数编程的for循环生成方法,但后来我不知道如何从其他地方调用这些方法.Heeeelp!

Sha*_*ger 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)
Run Code Online (Sandbox Code Playgroud)

定义时,__getattr__只要在实例本身找不到属性,就会在具有被访问属性名称的实例上调用.然后通过调用getattr查找包含的对象上的属性并返回它来委托包含的对象.每次进行动态查找都会花费很少,所以如果你想避免它,你可以在第一次请求时懒得缓存属性__getattr__,因此后续访问是直接的:

def __getattr__(self, name):
     attr = getattr(self.refClass, name)
     setattr(self, name, attr)
     return attr
Run Code Online (Sandbox Code Playgroud)

  • 别客气。警告:如果您在 3.4 版之前的 Python 参考解释器上运行(他们 [最终修复了对象终结](https://docs.python.org/3/whatsnew/3.4.html#pep-442-safe -object-finalization)),您的问题中的设计肯定会创建一个参考循环。如果循环中涉及的*任何*对象具有`__del__`清理方法,那么3.4之前的循环垃圾收集器无法处理它,并且每次创建这样的对象时都会泄漏内存并且不会显式破坏在失去对它的最后一个引用之前的循环(通过清除属性)。 (2认同)