updated 2010-06-15T09:45:00Z
:
- 「インスタンスとしてのクラス」アプローチの例と、「クラスとしてのインスタンス」アプローチの説明を追加しました。Alex Martelliの回答を組み込み、参照しました。
Python でプロトタイプの継承を実装する方法を考えています。この問題には、インスタンスとしてのクラスとクラスとしてのインスタンスという 2 つの異なるアプローチがあるようです。
2 番目の方法は、さまざまなタイプの既存のオブジェクトに適用できるという点で、より柔軟に見えますが、最初の方法は、典型的なユース ケースにより便利である可能性があります。
インスタンスとしてのクラス
ここでの考え方は、メタクラスを使用してインスタンス化を実際にオブジェクトではなくクラスにすることです。このアプローチは次のようになります。
class ClassAsInstance(type):
""" ClassAsInstance(type)\n
>>> c = ClassAsInstance()
>>> c.prop = 6
It's sort of annoying to have to make everything a class method.
>>> c.jef = classmethod(lambda self: self.prop)
>>> c.jef()
6
>>> cc = c()
>>> cc.jef()
6
But it works.
>>> c.prop = 10
>>> cc.jef()
10
>>> c.jef = classmethod(lambda self: self.prop * 2)
>>> cc.jef()
20
"""
def __new__(self):
return type(self.__name__ + " descendant", (self, ), {})
このアプローチで複雑なことを実際にテストしたことはないので、制限があるかもしれません。
クラスとしてのインスタンス
このアプローチでは、type
コンストラクターを使用してオブジェクトからクラスを作成するという考え方です。これはAlex Martelli の answerに例示されていますが、このアプローチで彼が使用する例では、子孫がプロトタイプへの後の変更を継承できるようにするのではなく、コピー プロトタイプを実装しています。
私のアプローチは、次のようなことをすることでした:
def createDescendant(obj):
return type(obj.__class__.__name__ + " descendant", (obj.__class__, ), obj.__dict__)()
これは、一種の javascript-y の方法で機能します。特定のオブジェクトへの変更は、その子孫には影響しませんが、親オブジェクト__class__
( javascript などprototype
) の変更には影響しません。これは、type
コンストラクターがある種の mro-ish スキームで参照するのではなく、コピーするためだと思います。 obj.__dict__
オブジェクトが親オブジェクトへの更新を継承する、真のプロトタイプ継承を可能にする改良版の実装を試みました。アイデアは、プロトタイプ オブジェクトの__dict__
プロパティを、新しく作成されたクラス (子孫オブジェクトのクラスになるクラス) の同じプロパティに割り当てることでした。
ただし、これはうまくいきませんでし__dict__
たtype
。この制限は、 から派生したクラスにも適用されますtype
。イテラブルやシーケンスなどで行われるように、「型プロトコルを実装する」オブジェクトを作成することでこの問題を回避できるかどうか、まだ興味がありますが、実際には から継承しませんtype
。これにより、アレックスが回答の最初の部分で言及した委任アプローチに固有の問題など、他の問題が発生する可能性があります。
委任
__getattr__
アレックスは、オブジェクトの状態が魔法のメソッドを介して子孫オブジェクトに伝播される、委任の 3 番目のアプローチも提案しています。繰り返しますが、例については Alex の回答と、このアプローチの制限の詳細を参照してください。
これらのアプローチの実用性に関するさらなる洞察と、代替提案がここに求められます。