有这样的代码:
>>> 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
显然,通话zope.interface.implements
以某种方式改变的属性和类的行为Foo
。
这是如何发生的呢? 我如何使用我的代码,这种做法?
示例代码的一部分zope.interface模块。
详细“发生了什么”
所述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)
除了最后的呼叫被推迟到首次创建的实例Foo
。
但为什么去这样的长度?
当zope.interface
首先被开发,巨蟒也没有上课装饰。
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
阅读源代码,卢克 :
http://svn.zope.org/zope.interface/trunk/src/zope/interface/declarations.py?rev=124816&view=markup
def _implements(name, interfaces, classImplements): frame = sys._getframe(2) locals = frame.f_locals # Try to make sure we were called from a class def. In 2.2.0 we can't # check for __module__ since it doesn't seem to be added to the locals # until later on. if (locals is frame.f_globals) or ( ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)): raise TypeError(name+" can be used only from a class definition.") if '__implements_advice_data__' in locals: raise TypeError(name+" can be used only once in a class definition.") locals['__implements_advice_data__'] = interfaces, classImplements addClassAdvisor(_implements_advice, depth=3)