详细的“发生了什么”
zope.interface.implements() 函数检查帧堆栈并更改构造中类的 locals() 命名空间(python dict)。 python 中class 语句中的所有内容都在该命名空间中执行,结果形成类体。
该函数为类命名空间添加了一个额外的值,__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 最初开发时,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