原文链接:https://blog.csdn.net/qq_19707521/article/details/79359858
类的实例化
在python中创建一个新式类时,一般都会定义一个 __init__
方法,用来对类的实例进行初始化。但是 __init__
方法并不是类的构造方法,类中真正的构造方法是 __new__
方法。
看看下面的例子:
class Test:
def __init__(self):
print('__init__ method in {}'.format(self.__class__))
def __new__(cls, *args, **kwargs):
print('__new__ method in {}'.format(cls))
return super(Test, cls).__new__(cls, *args, **kwargs)
test = Test()
# 输出为:
# __new__ method in <class '__main__.Test'>
# __init__ method in <class '__main__.Test'>
从上例可以看出,当实例化类时,类的 __new__
方法先被调用,然后是 __init__
方法。
一般来说, 类的 __new__
方法和 __init__
方法都会是下面的形式:
def __new__(cls, *args, **kwargs):
# do something
obj = ...
return obj
def __init__(self, *args, **kwargs):
# do something
对于类的 __new__
方法和 __init__
方法可以概括为:
-
__new__
方法是Python的新式类中真正的构造方法,负责创建并返回实例,因此,__new__
方法必须要有返回值; -
__init__
方法是初始化方法,负责初始化__new__
方法返回的实例对象。
类的 __new__
方法的特性
__new__
方法是新式类中的方法,它具有以下特性:
-
是进行类的实例化时第一个被调用的方法,将返回实例对象;
-
始终都是类方法(即第一个参数为
cls
),即使没有加上@classmethod
装饰器;扫描二维码关注公众号,回复: 5860083 查看本文章 -
该方法的第一个参数
cls
代表当前正在实例化的类,如果要得到当前类的实例,应当调用当前类的父类的__new__
方法;
重写 __new__
方法
如果(新式)类中没有重写 __new__
方法,默认是调用该类的直接父类的 __new__
方法来创建类的实例。如果该类的父类也没有重写__new__
方法,那么将一直按照继承链向上追溯至 object
类的 __new__
方法。
如果(新式)类中重写了 __new__
方法,那么可以选择任意一个其他新式类(必须是新式类,只有新式类有 __new__
方法,因为 object
类是所有新式类的基类)的 __new__
方法来创建实例,其中包括这个新式类的父类和子孙类,只要它们不会造成递归死循环。
看看下面的例子:
class Animal(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
"""
这里的object.__new__(cls, *args, **kwargs) 也可以写成如下形式:
1. super(Animal, cls).__new__(cls, *args, **kwargs)
2. object.__new__(Animal, *args, **kwargs)
3. Cat.__new__(cls, *args, **kwargs)
4. People.__new__(cls, *args, **kwargs) 即使People类和Animal类没有关系,也是可以调用的;
在任何新式类中,不能调用自身的 ‘__new__’ 方法来创建实例,因为这样会造成死循环。
所以要避免如下形式的调用:
return Animal.__new__(cls, *args, **kwargs)
return cls.__new__(cls, *args, **kwargs)
"""
print('call __new__ method for {}'.format(obj.__class__))
return object
class Cat(Animal):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
print('call __new__ method for {}'.format(obj.__class__))
return obj
class People(object):
# 该类没有 '__new__' 方法,那么会自动调用其父类,即object类的 '__new__' 方法来创建实例。
pass
class Girl(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(Cat)
print('call __new__ method for {}'.format(obj.__class__))
return obj
dog = Animal()
cat = Cat()
tina = Girl()
# 输出为:
# call __new__ method for <class '__main__.Animal'>
# call __new__ method for <class '__main__.Cat'>
# call __new__ method for <class '__main__.Cat'>
类的 __init__
方法的调用
类的 __new__
方法决定是否使用该类的 __init__
方法,因为类的 __new__
方法可以调用其他类的构造方法或者直接返回别的类实例作为本类的实例。
通常来说,新式类进行实例化时,__new__
方法会返回当前类的实例,然后调用该类的 __init__
方法进行实例的初始化。但是,如果 __new__
方法返回的不是当前类的实例,那么,当前类的 __init__
方法就不会被调用。
请看下面的例子:
class A:
def __init__(self, *args, **kwargs):
print('call __init__ method from {}'.format(self.__class__))
def __new__(cls, *args, **kwargs):
obj = super(A, cls).__new__(cls, *args, **kwargs)
print('call __new__ method for {}'.format(obj.__class__))
return obj
class B:
def __init__(self, *args, **kwargs):
print('call __init__ method from {}'.format(self.__class))
def __new__(cls, *args, **kwargs):
obj = super(B, cls).__new__(A, *args, **kwargs)
print('call __new__ for {}'.format(obj.__class__))
return obj
b = B()
print(type(b))
# 输出为:
# call __new__ for <class '__main__.A'>
# <class '__main__.A'>
可以看到,类B在实例化时并未调用自身的的初始化方法 __init__
。因为类B的构造方法返回的是类A的实例。