8

クラスにカスタム メタクラスがあり、作成時にクラスのクラス メソッドを呼び出す場合があります。

class Metaclass(type):
    def __new__(cls, name, bases, attrs):
        ...
        new_class = super(Metaclass, cls).__new__(cls, name, bases, attrs)
        ...
        new_class.get_fields() # do something
        ...
        return new_class

class FooBar(object):
    __metaclass__ = Metaclass

    @classmethod
    def get_fields(cls):
        ...

(そのようなコードの例はTastypieにあります。)

問題は、私がやりたいかどうかです:

class NewBar(FooBar):
    @classmethod
    def get_fields(cls):
        super(NewBar, cls).get_fields()
        ...

NewBarが呼び出された時点でまだ作成されていないため、これは機能しませんsuper(プログラム フローはまだメタクラスにあります)。それで、回避策はありますか?

おそらくget_fieldsメソッドがメタクラスのメソッドになる可能性があることはわかっていますが、これにより継承の実装がはるかに難しくなります (新しいメタクラスとクラス自体の両方を定義する必要があり、このクラスを拡張したい開発者には不向きです)。

(Python 2.7)

4

3 に答える 3

2

NewBarが呼び出されたときに使用できない場合でもget_fields、次のMROで見つけることができますcls

@classmethod
def get_fields(cls):
    # we can get invoked before NewBar is available in globals,
    # so get NewBar from cls.__mro__
    NewBar = next(c for c in cls.__mro__
                  if c.__module__ == __name__ and c.__name__ == 'NewBar')
    super(NewBar, cls).get_fields()
    ...

このコードは面白そうに見えますが、正しく機能し、質問で提案された代替案よりも大幅に単純です。super定数以外の最初の引数(unqualifiedなど)を使用したほとんどの呼び出しsuper(cls, cls)は正しくなく、継承を中断しますが、ジェネレータ式は。を取得するための型破りな方法にすぎないため、これは安全ですNewBar

MROでクラスを探すときは、クラス名とモジュール名の両方をチェックして(Mitarが指摘している__name__ように、として利用可能)、から継承する場合の誤検知を回避します。othermodule.NewBarthismodule.NewBar

于 2012-10-06T07:30:42.013 に答える
0

@ user4815162342からの回答に基づいて、私はさらに簡単な解決策を見つけました:

try:
    super(NewBar, cls).get_fields()
except NameError, e:
    if 'NewBar' in str(e):
        super(cls, cls).get_fields()
    else:
        raise
于 2012-10-06T08:09:37.720 に答える