如何在函数被调用的类声明里面?(How does the function that is call

2019-07-03 17:11发布

有这样的代码:

>>> 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模块。

Answer 1:

详细“发生了什么”

所述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


Answer 2:

阅读源代码,卢克 :

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) 


文章来源: How does the function that is called inside the class declaration?