1

cpython 2.5、2.7、3.2、およびメタクラスを__new__使用した pypy で、python 2 / python 3 と互換性のあるメタクラスの使用方法を使用するとオーバーライドされる奇妙な動作が見つかりました。

モジュール m1 が与えられた場合:

class C1Meta(type):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)

C1 = C1Meta('C1', (object,), {})


class C2Meta(type):
    pass

C2 = C2Meta('C2', (object,), {})

そして、次のメインプログラム:

import m1

C10 = m1.C1Meta('C10', (m1.C1,), {})


class C11Meta(m1.C1Meta):
    pass

C11 = C11Meta('C11', (m1.C1,), {})


class C12Meta(m1.C1Meta):
    def __new__(cls, name, bases, dct):
        return m1.C1Meta.__new__(cls, name, bases, dct)

C12 = C12Meta('C12', (m1.C1,), {})


class C13Meta(m1.C1Meta):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)

C13 = C13Meta('C13', (m1.C1,), {})


C20 = m1.C2Meta('C20', (m1.C2,), {})


class C21Meta(m1.C2Meta):
    pass

C21 = C21Meta('C21', (m1.C2,), {})


class C22Meta(m1.C2Meta):
    def __new__(cls, name, bases, dct):
        return m1.C2Meta.__new__(cls, name, bases, dct)

C22 = C22Meta('C22', (m1.C2,), {})


class C23Meta(m1.C2Meta):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)

C23 = C23Meta('C23', (m1.C2,), {})


print(C10)
print(C11)
print(C12)
print(C13)

print(C20)
print(C21)
print(C22)
print(C23)

スクリプトを実行すると、次の出力が生成されます (上記のすべての Python バージョンを含む)。

<class 'm1.C10'>
<class 'm1.C11'>
<class 'm1.C12'>
<class '__main__.C13'>
<class '__main__.C20'>
<class '__main__.C21'>
<class '__main__.C22'>
<class '__main__.C23'>

-> C10、C11、および C12 クラス モジュールが間違っています。

それは予想される動作ですか?

問題を起こさないnewをオーバーライドする方法はありますか?

ありがとう、

クリストフ

4

1 に答える 1

1

明らか__module__に、メタクラスの実行時に属性が設定されます。あなたの場合、メタクラスは内部で実行されm1ます。通常定義されたクラスでは、__module__属性が自動的に生成され、メタクラスに渡されます。ただし、メタクラスを手動で呼び出してクラスを作成し、空の属性辞書を渡しています。__module__したがって、クラスは属性を提供しません。__module__属性は自動的に作成されますが、 が呼び出されるまで作成されませんtype.__new__。これは modulem1の内部で行われるため、そのときに__module__作成された は を参照しm1ます。

メタクラスを明示的に呼び出す理由が正確にはわかりません。メタクラスの要点は、classステートメントを使用してクラスを定義したときに何が起こるかをカスタマイズできるようにすることです。ステートメントを使用したくない場合はclass、通常の関数を使用してクラスを作成するだけでよく、メタクラスを気にする必要はまったくありません。

とはいえ、たとえば、次のようにすることで、目的の動作を得ることができると思います。

C11 = C11Meta('C11', (m1.C1,), {'__module__': __name__})
于 2012-08-25T21:16:43.517 に答える