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__
?
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? Which methods are bound and which are free? Why are you able to call self.__init__()
but not cls.__init__()
? Is cls.__init__
a method defined in cls
itself or in its metaclass?
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.
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 ). For a staticmethod like __new__
, that means no arguments are automatically bound, so cls
has to be passed explicitly. 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__
.
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.
According to the docs:
__new__()
is a static method (special-cased so you need not declare it as such)
__init__
on the other hand, is a proper instance method. 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
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. 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. 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.
>>> 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. self.__init__
is a bound method which lacks the first parameter of 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. 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. Try this instead:
>>> cls.__init__(self)
cls
stands for class itself, while self
stands for object itself. These are just conventions.
The __new__
method is called before the object is created, in fact, __new__
should create the object and return it. 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.
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. __init__
is the method of instance. 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. So for class, it has its own __new__
and __init__
which are used by metaclass
to create class and initialize class.
These are meta programming of Python, I suggest to read the ninth chapter of Python Cookbook.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.