我用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
呢?
答案 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 将是类,并将其作为元类。