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.
该zope.interface.implements()
函数检查帧堆栈并更改构造类的locals()
命名空间(python dict
).class
python中语句中的所有内容都在该命名空间中执行,结果形成了类主体.
该函数为类命名空间添加了一个额外的值,__implements_advice_data__
包括一些数据(您传递给函数的接口,以及classImplements
稍后将使用的可调用的接口).
然后,通过__metaclass__
在命名空间中添加(或更改预先存在的)键,可以在相关类的元类中添加或链接.这样可以确保将来每次创建类的实例时,都会首先调用现在安装的元类.
事实上,这个元类(班级顾问)有点狡猾; 它在您第一次创建实例后再次自行删除.它简单地调用__implements_advice_data__
与传递给原始implements()
函数的接口一起指定的回调,在它__metaclass__
从类中删除键之后,或者用原始函数替换它__metaclass__
(它调用它来创建第一个类实例).回调自行清理,它__implements_advice_data__
从类中删除属性.
总之,所有工作zope.interface.implements()
都是:
__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)