在类中所有实例方法调用后自动调用方法:元类还是装饰器?

2024-05-19 19:17:37 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有课

class Foo:
    def __init__(self):
        pass
    def meth1(self, *args):
        do_stuff()
    def meth2(self, **kwargs):
        more_stuff()
    def callme(self):
        print "I'm called!"

我想巧妙地修改它,以便在执行meth1meth2和其他所有操作之后调用callme()。我该怎么做?我从来没有使用过类装饰器或元类,所以我不确定哪种方式是正确的,以及如何正确地使用它们。在

对于元类,我将以下内容组合在一起:

^{2}$

有一个班级装饰师:

def addcall_deco(cls):
    dct = {}
    for k, v in cls.__dict__.items():
        if isinstance(v, FunctionType) and k != 'callme':
            def newv(self, *args, **kwargs):
                v(self, *args, **kwargs)
                self.callme()
            cls.k = newv
    return cls

这两种方法似乎都适用于我的超级简单示例:

In [75]: Foo()
I'm called!
Out[75]: <__main__.Foo instance at 0x21ed680>

是否有明显的理由使用其中一个而不是另一个(例如特定的角落案例等)?我还认为我可以使用__new__,但是从常识的角度来看,我想修改类,而不是它的所有实例。在


Tags: selffooinitdefargspasskwargsclass
2条回答

实际上,您在这里使用元类作为类装饰器,而不是真正需要元类允许的更灵活的东西。在

因此,两个实现是相同的,您应该使用更简单的方法-类装饰器。至于“向后兼容性”——这不是一个你在新项目中应该担心的问题。在

当然,由于“长期支持”版本,很多服务器都在运行一些非常旧的Linuxes,并且有2.4或2.5版本的Python版本,但是如果 您的项目确实是在这样一个较旧的服务器上使用的,用户可以随时安装一个更新到足够支持的Python作为普通用户-不需要使用系统Python。在

附带说明:小心包装器,如果有返回值的话,您将丢弃包装好的方法返回值。方法是:

 def newv(self, *args, **kwargs):
      result = v(self, *args, **kwargs)
      self.callme()
      return result

最后,如果您认为您在处理的任何项目中都需要这种方法,请看一下“Aspect Oriented Programing”-有几个项目允许在Python中使用面向方面的方法,而无需对工具链或工作方式进行许多更改。在

旧版本的Python不支持类decorator,因此如果需要考虑向后兼容性,则需要使用元类或将类decorator转换为包装类的函数调用。在

相关问题 更多 >