4

次のコードはコンパイルされません。それは言う

NameError:名前'フィールド'が定義されていません

最後の行に。課題に到達__new__するまで呼び出されないからですか?fields私は何をすべきか?

class Meta(type):
    def __new__(mcs, name, bases, attr):
        attr['fields'] = {}
        return type.__new__(mcs, name, bases, attr)

class A(metaclass = Meta):
    def __init__(self, name):
        pass

class B(A):
    fields['key'] = 'value'

編集:

タイミングの問題ではないことがわかりました。名前の非表示に問題があります。A.fields代わりに書くとうまくいきます。

fieldsなぜ使えないのか知りたいのですがsuper().fields

4

1 に答える 1

4

fields['key'] = 'value'メタクラスの機械が作動する前に実行します。

class foo(object):
    var1 = 'bar'

    def foobar(self):
        pass

Pythonがclassステートメントにヒットすると、新しいローカル名前空間に入ります。

  1. var1 = 'bar'ステートメントを評価します。これはと同等ですlocals()['var1'] = 'bar'

  2. 次に、def foobarステートメントを評価します。これはと同等ですlocals()['var'] = the result of compiling the function

  3. 次にlocals()、クラス名、継承されたクラス、およびメタクラスとともに、メタクラス__new__メソッドに 渡します。例の場合、メタクラスは単純typeです。

  4. 次に、新しいローカル名前空間を終了__new__し、外部名前空間から返されたクラスオブジェクトをという名前で貼り付けfooます。

A.fieldsクラスAはすでに作成されており、上記のプロセスはにMetaインストールfieldsして実行されているため、コードは使用時に機能しますA

スーパーの実行時にスーパーに渡すようにsuper().fieldsクラス名が定義されていないため、使用できません。Bつまり、必要になりますsuper(B).fieldsが、 クラスの作成後にB定義されます。

アップデート

質問に対する私のコメントへの返信に基づいて、あなたが望むことを実行するいくつかのコードがあります。

def MakeFields(**fields):
    return fields

class Meta(type):
    def __new__(mcs, name, bases, attr):
        for base in bases:
            if hasattr(base, 'fields'):
                inherited = getattr(base, 'fields')
                try:
                    attr['fields'].update(inherited)
                except KeyError:
                    attr['fields'] = inherited
                except ValueError:
                    pass
        return type.__new__(mcs, name, bases, attr)

class A(metaclass=Meta):
    fields = MakeFields(id='int',name='varchar') 

class B(A):
    fields = MakeFields(count='int')

class C(B):
    pass

class Test(object):
    fields = "asd"

class D(C, Test):
    pass

print C.fields
print D.fields
于 2010-09-16T06:05:10.403 に答える