如何在类声明中调用函数?

def*_*fuz 3 python zope metaprogramming zope.interface

有这个代码:

>>> class Foo:
...     zope.interface.implements(IFoo)
...
...     def __init__(self, x=None):
...         self.x = x
...
...     def bar(self, q, r=None):
...         return q, r, self.x
...
...     def __repr__(self):
...         return "Foo(%s)" % self.x
Run Code Online (Sandbox Code Playgroud)

Obviously, the call of zope.interface.implements in some way alters the properties and behavior of the class Foo.

How does this happen? How do I use this approach in my code?

Example code is the part of zope.interface module.

Mar*_*ers 6

详细的"会发生什么"

zope.interface.implements()函数检查帧堆栈并更改构造类的locals()命名空间(python dict).classpython中语句中的所有内容都在该命名空间中执行,结果形成了类主体.

该函数为类命名空间添加了一个额外的值,__implements_advice_data__包括一些数据(您传递给函数的接口,以及classImplements稍后将使用的可调用的接口).

然后,通过__metaclass__在命名空间中添加(或更改预先存在的)键,可以在相关类的元类中添加或链接.这样可以确保将来每次创建类的实例时,都会首先调用现在安装的元类.

事实上,这个元类(班级顾问)有点狡猾; 它在您第一次创建实例后再次自行删除.它简单地调用__implements_advice_data__与传递给原始implements()函数的接口一起指定的回调,在它__metaclass__从类中删除键之后,或者用原始函数替换它__metaclass__(它调用它来创建第一个类实例).回调自行清理,它__implements_advice_data__从类中删除属性.

简短的版本

总之,所有工作zope.interface.implements()都是:

  • 将传递的接口与回调一起添加到class(__implements_advice_data__)中的特殊属性.
  • 确保在第一次使用特殊元类创建实例时调用回调.

最后,它是道德等同于定义你的接口,如下所示:

class Foo:
    def __init__(self, x=None):
        self.x = x

    def bar(self, q, r=None):
        return q, r, self.x

    def __repr__(self):
        return "Foo(%s)" % self.x

zope.interface.classImplements(Foo, IFoo)
Run Code Online (Sandbox Code Playgroud)

除了最后一次调用被推迟,直到你第一次创建一个实例Foo.

为什么要这么长呢?

什么时候zope.interface开发,Python还没有类装饰器.

zope.interface.classImplements()需要单独调用一个函数,类创建后,和zope.interface.implements()通话类主体提供关于接口的类器具更好的文档.您可以将它放在类声明的顶部,每个人在查看课程时都可以看到这条重要的信息.在类声明之后进行classImplements()呼叫并不是那么明显,而且对于长类定义,它很容易被完全遗漏.

PEP 3129最终确实为该语言添加了类装饰器,并将它们添加到python 2.6和3.0中; zope.interface最初是在python 2.3(IIRC)时代开发的.

现在我们已经有了类装饰器,zope.interface.implements()已被弃用,您可以使用zope.interface.implementer类装饰器:

@zope.interface.implementer(IFoo)
class Foo:
    def __init__(self, x=None):
        self.x = x

    def bar(self, q, r=None):
        return q, r, self.x

    def __repr__(self):
        return "Foo(%s)" % self.x
Run Code Online (Sandbox Code Playgroud)