詳細な「何が起こるか」
この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はついにクラスデコレータを言語に追加し、それらはpython2.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