在python中实例化元类

时间:2019-01-12 10:41:02

标签: python metaclass

我用python编写了一个类,该类继承自type。我认为这是一个类的唯一要求,以便被称为元类,但尚未为其定义__new__方法。但是在将这个新类实例化为元类时,出现了以下错误:

TypeError: type.__new__() takes exactly 3 arguments (0 given)

以下是我的代码:

class a(type) :
    pass 
c= a()

现在,当我处理类语句时,正在调用__new__的{​​{1}}方法。这是因为python中所有类的默认元类都是type

现在,当我实例化类type时,假设从(a继承的任何类都是元类,我假定它是元类,它与创建一个类?为什么这不会导致用正确的参数调用type呢?

2 个答案:

答案 0 :(得分:4)

这不起作用:

class a(type) :
    pass 
c = a()

...出于同样的原因,该方法也不起作用:

c = type()

最后,两者都一样。

要将其用作元类,请执行以下操作:

>>> class Class(metaclass=a):
...     pass
...
>>> Class
<class '__main__.Class'>
>>> type(Class)
<class '__main__.a'>

您也可以按照尝试直接实例化该类,但必须提供正确的参数:

AnotherClass = type('AnotherClass', (), {})

YetAnotherClass = a('YetAnotherClass', (), {})

答案 1 :(得分:1)

此错误是由于您不尊重type的签名所致。

type继承确实足够了 用作类的元类,但实际上您必须使用作为元类

type本身具有“两种工作模式:如果使用 3 个位置参数调用,则会创建一个 new 类。然后是 type 是该类的元类。如果使用 1 位置参数调用,它将根本不创建新的类或对象-而是仅返回该对象的类。

但是用 no 参数调用type根本没有意义。并且上述模式中的参数不是可选的。因此,如果您尝试完全不使用任何参数来调用类型,那么您将得到一个TypeError,这不是“ TypeError,因为类型类出错了”,而是“ TypeError,因为您的调用没有匹配可调用签名”。

type继承并且不做任何更改时,您的类的行为将与原始type完全相同:您可以使用 one 进行调用三个位置自变量,负责在任一模式下工作的代码位于type.__new__中。

现在,如果您想将您的类用作元类,则可以调用它,但是可以使用以下三个参数形式:为其赋新类名,其基数和属性-实际上可以为空,但是您必须传递一个字符串,一个元组和一个字典作为这三个参数:

class A(type): pass

myclass = A("", (), {})

现在,A作为myclass的元类:

In [16]: type(myclass)                                                                                   
Out[16]: __main__.A

但是,每当定义一个元类时,在声明类主体时,通常将其与metaclass=命名参数一起使用:

In [17]: class  MyOtherClass(metaclass=A): 
    ...:     pass 
    ...:                                                                                                 

In [18]: type(MyOtherClass)                                                                              
Out[18]: __main__.A

Python的运行时然后将编译该类主体,并在执行其字节码时,将调用您的元类的__new__(然后依次为__init__和其{{ 1}})方法,使其可以用作元类。

因此,以防万一还不清楚:当您从__prepare__派生一个打算将其用作元类的类时,无需进一步实例化它以说“它现在是一个元类”。 。类型的子类已经可以是元类,并且其 instances 将是类,并将其作为元类。