详细的“发生了什么”
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时期首次开发的(如果我没记错)。
现在我们有了类装饰器, 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
@implementer
装饰器。 - Gareth Latty