4

メタクラスと多重継承に関する 2 つの質問があります。1 つ目は、クラスでは TypeError が発生するのに では発生しないのはなぜDerivedですかDerived2?

class Metaclass(type): pass

class Klass(object):
    __metaclass__  = Metaclass

#class Derived(object, Klass): pass # if I uncomment this, I get a TypeError

class OtherClass(object): pass

class Derived2(OtherClass, Klass): pass # I do not get a TypeError for this

正確なエラー メッセージは次のとおりです。

TypeError: Error when calling the metaclass bases Cannot create a consistent method resolution order (MRO) for bases object, Klass

super2 番目の質問は次のとおりです。この場合、なぜ機能しないのですか (__init__代わりにを使用すると__new__super再び機能します):

class Metaclass(type):
    def __new__(self, name, bases, dict_):
        return super(Metaclass, self).__new__(name, bases, dict_)

class Klass(object):
    __metaclass__  = Metaclass

そこに私は得る:

TypeError: Error when calling the metaclass bases type.__new__(X): X is not a type object (str)

Python 2.6 を使用しています。

4

4 に答える 4

7

2番目の質問はすでに2回回答されていますが、__new__実際には静的メソッドであり、コメントで誤って主張されているクラスメソッドではありません...:

>>> class sic(object):
...   def __new__(cls, *x): return object.__new__(cls, *x)
... 
>>> type(sic.__dict__['__new__'])
<type 'staticmethod'>

最初の質問 (誰かが指摘したように) はメタクラスとは関係ありません。B が AEg のサブクラスである場合、この順序で任意の 2 つのクラス A と B から乗算継承することはできません。

>>> class cis(sic): pass
... 
>>> class oops(sic, cis): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases sic, cis

MRO は、左端のベースが右端のベースより先にアクセスされることを保証しますが、祖先の中で x が y のサブクラスである場合、x が y の前にアクセスされることも保証します。この場合、これらの保証の両方を満たすことは不可能です。もちろん、これらの保証には正当な理由があります: それらがなければ (例えば、サブクラスの制約ではなく、メソッド解決の左右の順序のみを保証する古いスタイルのクラスでは)、x のすべてのオーバーライドは無視され、y の定義が優先されます。 、そしてそれはあまり意味がありません。考えてみてください:最初に継承し、次に他のクラスから継承するとはどういう意味でしょうか? objectそれかobjectの (本質的に存在しない;-) いくつかの特別なメソッドの定義は、他のクラスのオーバーライドよりも優先されなければならず、他のクラスのオーバーライドが無視されますか?

于 2010-02-05T02:53:12.987 に答える
4

最初の質問については、Python での MRO の説明、具体的には「メソッド解決順序の誤り」セクションを参照してください。本質的には、Python がオブジェクトとクラスのメソッドのどちらを使用するかを認識していないという事実に関係しています。(メタクラスの使用法とは関係ありません。)

__new__2 番目の質問については、関数の仕組みを誤解しているようです。それ自体への参照は最初の引数として取りません。インスタンス化されるクラスの型への参照を取ります。したがって、コードは次のようになります。

class Metaclass(type):
    def __new__(cls, name, bases, dictn):
        return type.__new__(cls, name, bases, dictn)
于 2010-02-04T23:26:02.827 に答える
0

どうして?

class Derived(object, Klass):

Klassはすでにオブジェクトから派生しています。

class Derived(Klass):

ここで合理的なことです。

于 2010-02-05T07:23:01.600 に答える
0

__new__2 番目の質問では、次のように self を渡す必要があります。

class Metaclass(type):
    def __new__(self, name, bases, dict_):
        return super(Metaclass, self).__new__(self, name, bases, dict_)

class Klass(object):
    __metaclass__  = Metaclass

これがなぜなのか頭の中で思い出すことはできませtype.__new__んが、バインドされたメソッドではないため、魔法のように自己引数を取得できないためだと思います。

于 2010-02-04T23:28:44.987 に答える