20

私はメタクラスを書いていましたが、誤って次のようにしました。

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type(name, bases, dict)

...このようにではなく:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type.__new__(cls, name, bases, dict)

これら2つのメタクラスの違いは正確には何ですか?より具体的には、最初のクラスが正しく機能しなかった原因は何ですか(一部のクラスはメタクラスによって呼び出されませんでした)?

4

6 に答える 6

12

最初の例では、まったく新しいクラスを作成しています。

>>> class MetaA(type):
...     def __new__(cls, name, bases, dct):
...         print 'MetaA.__new__'
...         return type(name, bases, dct)
...     def __init__(cls, name, bases, dct):
...         print 'MetaA.__init__'
... 
>>> class A(object):
...     __metaclass__ = MetaA
... 
MetaA.__new__
>>> 

2番目のケースでは、親のを呼び出しています__new__

>>> class MetaA(type):
...     def __new__(cls, name, bases, dct):
...         print 'MetaA.__new__'
...         return type.__new__(cls, name, bases, dct)
...     def __init__(cls, name, bases, dct):
...         print 'MetaA.__init__'
... 
>>> class A(object):
...     __metaclass__ = MetaA
... 
MetaA.__new__
MetaA.__init__
>>> 
于 2010-04-09T16:34:27.193 に答える
8

以下の注釈を参照してください。これがお役に立てば幸いです。

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        # return a new type named "name",this type has nothing
        # to do with MetaCls,and MetaCl.__init__ won't be invoked
        return type(name, bases, dict)

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        # return a new type named "name",the returned type 
        # is an instance of cls,and cls here is "MetaCls", so 
        # the next step can invoke MetaCls.__init__ 
        return type.__new__(cls, name, bases, dict)
于 2014-10-11T04:23:03.457 に答える
8

最初に理解する必要があるのは、どのように機能するかobject.__new__()です。

これは以下のドキュメントからのものです:

object.__new__(cls[, ...])

クラスの新しいインスタンスを作成するために呼び出されますcls__new__()は静的メソッド(特別な場合なので、そのように宣言する必要はありません)であり、インスタンスが要求されたクラスを最初の引数として受け取ります。残りの引数は、オブジェクトコンストラクター式(クラスの呼び出し)に渡される引数です。の戻り値は__new__() 、新しいオブジェクトインスタンス(通常はのインスタンスcls)である必要があります。

__new__()通常の実装では、適切な引数を使用してスーパークラスのメソッドを呼び出し、super(currentclass, cls).__new__(cls[, ...])必要に応じて新しく作成されたインスタンスを変更してから返すことにより、クラスの新しいインスタンスを作成します。

__new__()のインスタンスを返す場合cls、新しいインスタンスの__init__()メソッドはのように呼び出されます__init__(self[, ...])。ここselfで、は新しいインスタンスであり、残りの引数はに渡されたものと同じ__new__()です。

__new__()のインスタンスを返さない場合cls、新しいインスタンスの__init__()メソッドは呼び出されません。

__new__()主に、不変タイプのサブクラス(、、、、など)がインスタンスの作成をカスタマイズできるようにすることを目的としてintstrますtuple。また、クラスの作成をカスタマイズするために、カスタムメタクラスでも一般的にオーバーライドされます。

したがって、mg。の回答では、前者は関数を呼び出さず__init__、後者はを呼び出した後に関数__init__を呼び出し__new__ます。

于 2016-06-04T04:44:43.100 に答える
5
return type(name, bases, dict)

これから得られるのは新しいtypeものであり、MetaClsインスタンスではありません。したがって、MetaCls(を含む__init__)で定義されたメソッドを呼び出すことはできません。

type.__new__はい、その新しい型の作成の一部として呼び出されますが、clsその関数に入る値はであり、ではtypeありませんMetaCls

于 2010-04-09T16:26:28.713 に答える
5
class MyMeta(type):
    def __new__(meta, cls, bases, attributes):
        print 'MyMeta.__new__'
        return type.__new__(meta, cls, bases, attributes)
    def __init__(clsobj, cls, bases, attributes):
        print 'MyMeta.__init__'

class MyClass(object):
  __metaclass__ = MyMeta
  foo = 'bar'

同じ結果を達成する別の方法:

cls = "MyClass"
bases = ()
attributes = {'foo': 'bar'}
MyClass = MyMeta(cls, bases, attributes)

MyMetaは呼び出し可能であるため、Pythonは特別なメソッドを使用します__call__

Pythonはのタイプ(この場合は)を検索__call__しますMyMetatype

「新しいスタイルのクラスの場合、特別なメソッドの暗黙的な呼び出しは、オブジェクトのインスタンスディクショナリではなく、オブジェクトのタイプで定義されている場合にのみ正しく機能することが保証されます。」

MyClass = MyMeta(...)次のように解釈されます:

my_meta_type = type(MyMeta)
MyClass = my_meta_type.__call__(MyMeta, cls, bases, attributes)

私の中には次のtype.__call__()ようなものを想像します:

MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes)
meta_class = MyClass.__metaclass__
meta_class.__init__(MyClass, cls, bases, attributes)
return MyClass

MyMeta.__new__()MyClassの構築方法を決定します:

type.__new__(meta, cls, bases, attributes)の正しいメタクラス(はMyMeta)を設定しますMyClass

type(cls, bases, attributes)のデフォルトのメタクラス(タイプ)を設定しますMyClass

于 2012-11-01T18:12:41.643 に答える
2

それはすべてここでかなりよく説明されています。

適切なタイプのオブジェクトを返さない場合、カスタムメタクラスを定義する意味はありません。

于 2010-04-09T15:49:21.700 に答える