[英]`__new__` and `__init__` on class and object
In Python 3, when defining a subclass, why do you need to use cls
as the first argument of __new__
, but not to use self
as the first argument of __init__
? 在Python 3中,定义子类时,为什么需要将cls
用作__new__
的第一个参数,而不需要将self
用作__init__
的第一个参数?
An example: 一个例子:
class MyClass(object):
def __new__(cls, *args, **kwargs):
return super(MyClass, cls).__new__(cls, *args, **kwargs) # with `cls`
def __init__(self, *args, **kwargs):
return super(MyClass, self).__init__(*args, **kwargs) # without `self`
When I compared these functions I got more confused: 当我比较这些功能时,我变得更加困惑:
>>> cls = object
>>> self = cls()
>>> cls.__new__ is self.__new__
True
>>> cls.__init__ is self.__init__
False
>>> self.__init__()
>>> cls.__init__()
Traceback (most recent call last): ...
So, what are the differences between __new__
and __init__
behind these results? 那么,这些结果背后的__new__
和__init__
有什么区别? Which methods are bound and which are free? 哪些方法是绑定的,哪些是免费的? Why are you able to call self.__init__()
but not cls.__init__()
? 为什么可以调用self.__init__()
但不能调用cls.__init__()
? Is cls.__init__
a method defined in cls
itself or in its metaclass? cls.__init__
是在cls
本身或其元类中定义的方法吗?
The biggest part of the picture you're probably missing is that __new__
is a staticmethod, special-cased to be one even if you don't use the @staticmethod
decorator. 你可能丢失图片的最大的部分是, __new__
是一个静态方法, 特例,是一个即使你不使用@staticmethod
装饰。
When calling a method through super()
, super()
performs the same kind of argument binding that would be performed normally for that kind of method (using the descriptor protocol ). 通过super()
调用方法时, super()
会执行与通常为该方法执行的相同类型的参数绑定(使用描述符协议 )。 For a staticmethod like __new__
, that means no arguments are automatically bound, so cls
has to be passed explicitly. 对于像__new__
这样的静态__new__
,这意味着不会自动绑定任何参数,因此必须显式传递cls
。 For an instance method like __init__
, that means self
is bound automatically, which is why you don't have to pass self
to super().__init__
. 对于类似__init__
的实例方法,这意味着self
是自动绑定的,这就是为什么您不必将self
传递给super().__init__
。
The main purpose of __new__
is to allocate a new instance of the class, while __init__
's job is to set up an existing instance. __new__
的主要目的是分配该类的新实例,而__init__
的工作是设置现有实例。
According to the docs: 根据文档:
__new__()
is a static method (special-cased so you need not declare it as such)__new__()
是静态方法(特殊情况,因此您无需这样声明)
__init__
on the other hand, is a proper instance method. 另一方面, __init__
是合适的实例方法。 It can be called multiple times on the same instance, by the way. 顺便说一下,可以在同一实例上多次调用它。
That should be enough to explain your terminal session: 这足以说明您的终端会话:
>>> cls = object
>>> self = cls()
You just called object.__call__
, which essentially does 您只是调用了object.__call__
,实际上
self = cls.__new__()
if isinstance(self, cls):
cls.__init__(self)
return self
Notice that the return value of __new__
is not required to be an instance of the class it belongs to, but __init__
is called only if it is. 请注意, __new__
的返回值__new__
它所属的类的实例,但是__init__
仅在它属于时才被调用。 In your case, it is. 就您而言。
>>> cls.__new__ is self.__new__
True
__new__
is a static method, so attempting to bind it to the instance does nothing: it stays a class method. __new__
是静态方法,因此尝试将其绑定到实例没有任何作用:它保留为类方法。 This is the same reason that you have to pass cls
explicitly when calling super().__new__
: it's the same free function, unbound to either class or instance. 这与调用super().__new__
时必须显式传递cls
原因相同super().__new__
:这是相同的自由函数,不绑定到类或实例。
>>> cls.__init__ is self.__init__
False
Not only are these not the same thing, but their types are different. 这些不仅是不一样的东西,而且它们的类型也不同。 cls.__init__
is a regular function. cls.__init__
是常规函数。 self.__init__
is a bound method which lacks the first parameter of cls.__init__
. self.__init__
是一个绑定方法,缺少cls.__init__
的第一个参数。
>>> self.__init__()
This has already been called, but for object
, it's a no-op you can call as many times as you like. 这已经被调用过,但是对于object
,这是一个空操作,您可以随意调用多次。 Notice that the first parameter is not being passed in, being as it is a bound method. 请注意,第一个参数未传入,因为它是绑定方法。
>>> cls.__init__()
This is calling the raw __init__
function, which requires that the self
parameter be passed in. Since you don't do that, it raises. 这是在调用原始的__init__
函数,该函数要求传入self
参数。由于您不这样做,它会引发。 Try this instead: 尝试以下方法:
>>> cls.__init__(self)
cls
stands for class itself, while self
stands for object itself. cls
代表类本身,而self
代表对象本身。 These are just conventions. 这些只是约定。
The __new__
method is called before the object is created, in fact, __new__
should create the object and return it. __new__
方法在对象创建之前被调用,实际上, __new__
应该创建对象并返回它。 Therefore, it needs a class to create object. 因此,它需要一个类来创建对象。 After that, the __init__
is called to initialize the object, so it needs the object as the first argument. 之后,将调用__init__
来初始化对象,因此它需要该对象作为第一个参数。
For example: 例如:
class MyClass:
def __new__(cls, *args, **kwargs):
# cls == MyClass
return super().__new__(cls, *args, **kwargs)
# cls here is because __new__ is staticmethods so you have to pass the cls explicitly
# You can't use cls() here because it will call this methods again and again
# causing recusion error
def __init__(self, *args, **kwargs):
# Here self is the instance(or object) of MyClass
# So you can initialize it by self.xxx
self.xxx = 'xxx'
__new__
is static method, so the class and instance share the same __new__
method. __new__
是静态方法,因此类和实例共享相同的__new__
方法。 __init__
is the method of instance. __init__
是实例的方法。 If you want to call it via class, you need to pass the instance as the first argument explicitly. 如果要通过类调用它,则需要将实例作为第一个参数显式传递。
cls.__init__(self)
Anything in Python is object, including the class itself. Python中的任何东西都是对象,包括类本身。 So for class, it has its own __new__
and __init__
which are used by metaclass
to create class and initialize class. 因此,对于类,它具有自己的__new__
和__init__
,它们由metaclass
用于创建类和初始化类。
These are meta programming of Python, I suggest to read the ninth chapter of Python Cookbook. 这些是Python的元编程,我建议阅读Python Cookbook的第9章。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.