1

__metaclass__クラスのプロパティと実際の継承の間で多くの混乱があり__new__、これらのシナリオのいずれかでどのように呼び出されるか。私の問題は、django フレームワークのいくつかのモデル コードを掘り下げることから来ています。

Meta子のサブクラスで定義されているように、クラスに属性を追加したいとしましょう。

class Parent(type):

    def __new__(cls, name, base, attrs):
        meta = attrs.pop('Meta', None)
        new_class = super(Parent, cls).__new__(cls, name, base, attrs)
        new_class.fun = getattr(meta, 'funtime', None)
        return new_class

django のコードで実際のメソッドが呼び出される理由がわかりませんが、__new__そのようなコードを作成しようとすると機能しません。

私が経験したことから、以下は実際__new__には親のメソッドを呼び出しません:

class Child(Parent):
    class Meta:
       funtime = 'yaaay'

C = Child()

これをやろうとすると、TypeError で文句を言います:

TypeError: __new__() takes exactly 4 arguments (1 given)

しかし、私が見てきたソース コードは、そのように動作するようです。

メタクラスで実行できることを理解しています:

class Child(object):
    __metaclass__ = Parent

__metaclass___しかし、配布可能なモジュールを作成する場合は非の方がクリーンになるため、なぜ彼らの方法が私ではなく彼らにとって機能するのかわかりません。

誰かが私が欠けているものについて正しい方向に向けてくれませんか?

ありがとう!

4

2 に答える 2

1

を拡張するメタクラスではtype__new__クラスを作成するために使用されます。

クラスで__new__は、インスタンスを作成するために使用されます。

メタクラスは、クラスを作成するクラスです。クラス継承とメタクラスを混同しています。

あなたのChildクラスは継承Parentしており、のインスタンスを作成したいと考えていますChild。ただし、ParentメタクラスであることParent.__new__は、クラスのインスタンスを作成するために使用すべきではないことを意味します。

于 2013-03-14T23:44:06.690 に答える
1

django ではModel、メタクラスではありません。実際、メタクラスはModelBase. だからこそ、彼らのやり方はうまくいき、あなたのやり方はうまくいかないのです。
さらに、最新の django はヘルパー関数 を使用してsix.with_metaclass「ModelBase」をラップしていました。

django のスタイルに従いたい場合ParentChildクラスは次のようになります。

def with_metaclass(meta, base=object):
    """Create a base class with a metaclass."""
    return meta("NewBase", (base,), {})

class ParentBase(type):
    def __new__(cls, name, base, attrs):
        meta = attrs.pop('Meta', None)
        new_class = super(ParentBase, cls).__new__(cls, name, base, attrs)
        new_class.fun = getattr(meta, 'funtime', None)
        return new_class

class Parent(with_metaclass(ParentBase)):
    pass

class Child(Parent):
    class Meta:
       funtime = 'yaaay'

c = Child()

>>> c.fun
'yaaay'

に注目しましょうParent。とほぼ同等です。

NewBase = ParentBase("NewBase", (object,), {})
class Parent(NewBase):
    pass
    

どう理解するかが鍵ParentBase("NewBase", (object,), {})
思い出してみましょうtype()

タイプ(名前、ベース、辞書)

3 つの引数を使用して、新しい型オブジェクトを返します。これは本質的に、class ステートメントの動的な形式です。name 文字列はクラス名であり、name属性になります。bases タプルは基本クラスを項目化し、bases属性になります。dict ディクショナリは、クラス本体の定義を含む名前空間であり、dict属性になります。たとえば、次の 2 つのステートメントは、同じ型のオブジェクトを作成します。

ParentBaseはメタクラスであるため、 のサブクラスですtype。したがって、ParentBase("NewBase", (object,), {})と非常によく似ていtype("NewBase", (object,), {})ます。この場合、唯一の違いは、動的に作成されたクラスが のインスタンスではなくtypeParentBase. つまり、 のメタクラスはNewBaseですParentBaseParentと同等です

class NewBase(object):
    __metaclass__ = ParentBase

class Parent(NewBase):
    pass
    

最後に、__metaclass__.

于 2013-03-15T00:02:01.650 に答える