17

クラスのメタクラスを設定するには、__metaclass__属性を使用します。メタクラスはクラスの定義時に使用されるため、クラス定義の後に明示的に設定しても効果はありません。

これは、メタクラスを明示的に設定しようとすると起こることです。

>>> class MetaClass(type):
    def __new__(cls, name, bases, dct):
        dct["test_var"]=True
        return type.__new__(cls, name, bases, dct)
    def __init__(cls, name, bases, dct):
        super(MetaClass, cls).__init__(name, bases, dct)


>>> class A:
    __metaclass__=MetaClass


>>> A.test_var
True
>>> class B:
    pass

>>> B.__metaclass__=MetaClass
>>> B.test_var

Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    B.test_var
AttributeError: class B has no attribute 'test_var'

私が考えることができる最良のアイデアは、クラス全体を再定義し、__metaclass__何らかの方法で属性を動的に追加することです。または、クラス定義の後にメタクラスを設定するより良い方法を知っていますか?

4

5 に答える 5

13

オブジェクトのクラスを変更できるのと同じ方法で、クラスの作成後にメタクラスを変更できますが、多くの問題があります。まず、最初のメタクラスは とは異なる必要があり、新しいメタクラスtype__init__および__new__は呼び出されません (手動でまたはのジョブ__init__を実行するメソッドを 呼び出すことはできます)。__init__

おそらく、メタクラスを変更する最も簡単な方法は、クラスを最初から再作成することです。

B = MetaClass(B.__name__, B.__bases__, B.__dict__)

しかし、メタクラスを動的に変更したい場合は、最初に B を一時的なカスタム メタクラスで定義する必要があります。

class _TempMetaclass(type):
    pass

class B:
    __metaclass__ = _TempMetaclass # or: type('temp', (type, ), {})

次に、次のようにメタクラスを定義できます。

class MetaClass(type):
    def __init__(cls, *a, **kw):
        super(MetaClass, cls).__init__(*a, **kw)
        cls._actual_init(*a, **kw)
    def _actual_init(cls, *a, **kw):
        # actual initialization goes here

そして、次のようにします。

B.__class__ = MetaClass
MetaClass._actual_init(B, B.__name__, B.__bases__, B.__dict__)

また、クラスのすべての初期化が完了していることを確認する必要があります_actual_initclassmethodメタクラスを変更するメタクラスに を追加することもできます。

どちらのソリューションにも、B のベースが制限されるというわずかな欠点があります。元のメタクラスと新しいメタクラスの両方と互換性がある必要がありますが、それは問題ではないと思います。

于 2011-02-25T18:55:07.423 に答える
5

メタクラスの目的は、属性アクセスを変更することではなく、クラスの作成をカスタマイズすることです。この__metaclass__属性は、クラス定義から型オブジェクトを構築するために使用される呼び出し可能オブジェクトを定義します。デフォルトはtype()です。したがって、この属性はクラスの作成時にのみ評価されます。すでに作成されているクラスのクラス作成をカスタマイズすることはできないため、後で変更しても意味がないことは明らかです。詳細については、Python言語リファレンス、3.4.3クラス作成のカスタマイズを参照してください。

メタクラスは、明らかにやりたいことに対して適切なツールではありません。既存のクラスに新しい属性を追加したいだけの場合は、それを割り当ててみませんか?

于 2011-02-25T18:21:56.880 に答える
2

classメタクラスはステートメントが何をするかを説明していると考えることができます。そのため、後でメタクラスを設定することは不可能です。クラス コードは既に型オブジェクトに変換されています。変更するには遅すぎます。

元の型を単純にサブクラス化して、メタクラスを追加できます。

class C(B):
    __metaclass__=MetaClass
于 2011-02-25T17:52:57.763 に答える
-4

なぜこれが必要なのですか?これが可能だとは思いませんが、ユースケースを説明できれば、おそらく代替案を提案できます。

クラス全体を再定義する行に沿って、できることは次のとおりです。

import types
NewClass = types.ClassType('NewClass', (object, ), {'__metaclass__':MetaClass})

次に、古いメソッドをすべてコピーします。

for item in dir(OldClass):
    setattr(NewClass, item, getattr(OldClass, item))
于 2011-02-25T17:53:21.937 に答える
-6

現在、これをテストすることはできません (現在、私のマシンで Python にアクセスすることはできません :-() が、メタクラスが不変でない限り、おそらく次のようなことを試すことができます:

>>> class B:
        pass
>>> setattr(B, "__metaclass__", MetaClass)

繰り返しますが、今はテストできないので、これが無効な回答である場合はお詫び申し上げます。:)

于 2011-02-25T17:48:49.647 に答える