3

このコードを持っています:

>>> 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何らかの方法で を呼び出すと、 class のプロパティと動作が変更されますFoo

これはどのように起こりますか?コードでこのアプローチを使用するにはどうすればよいですか?

サンプルコードはzope.interfaceモジュールの一部です。

4

2 に答える 2

6

詳細な「何が起こるか」

このzope.interface.implements()関数は、フレームスタックを検査し、構築中のクラスのlocals()名前空間(python )を変更します。dictPythonのステートメント内のすべて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はついにクラスデコレータを言語に追加し、それらはpython2.6および3.0に追加されました。zope.interfacePython 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
于 2012-11-11T11:23:05.263 に答える
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)
于 2012-11-10T15:17:35.483 に答える