这两个方法是 python 类中的基本方法, 经常会在一些面试中问到. 即便没有要面试之类的, 学习一下其内部的原理和使用也是有必要的.
首先区分一下这两个方法:
__init__: 初始化方法
__new__: 构造函数
__init__: 实例方法
__new__: 静态方法
__new__: 创建实例, 并返回 cls 实例, 也就是 init 方法的第一参数 self
__init__: 在 new 创建实例对象后调用, self 代表创建的这个实例对象, init 设置对象属性的初始值, 因此是实例方法, 并不返回值
一点小插曲:
__new__方法在继承自 object 的新式类中才有, 说到这里, 提一下新式类与经典类:
object 为所有类的基类
从 object 继承得来的类称为新式类, 没有继承 object 的为经典类
新式类和经典类的一个常见的差别在于其继承父类的方式, 新式类的搜索方式为广度优先, 而经典类为深度优先.(当然还有其他的, 有兴趣再查一下)
python2 默认经典类, python3 默认新式类, python2 可以显示继承 object(class A(object))
- def __init__(self, *args, **kwargs):
- pass
- def __new__(cls, *args, **kwargs):
- return object.__new__(cls, *args, **kwargs)
创建实例对象的过程:
上面给出了初始化方法和构造函数, 可以看到初始化方法没有返回值, 而构造函数有返回值.
首先, 在创建一个类的实例时, 先调用构造方法 (new), 他接受当前正在实例化的类作为第一参数 (cls), 然后返回创建产生的实例, 给__init__方法的第一参数 self, 让其进行初始值的设置.
我们在初学时经常会见到 init 方法, 但是很少见到 new 方法, 这里解释一下, new 方法经常不被重写, python 中默认调用了父类的 new, 如果父类没有就继续上溯, 直到 object 的 new 方法.(既然说是重写了, 那么就一定在他的祖先类中有这个方法, 最根本的就是 object 类, 他是所有新式类的基类)
文字也许看的有点懵, 那就举个例子:
- class A(object):
- """docstring for A"""
- def __init__(self, *args, **kwargs):
- print("init",self.__class__)
- def __new__(cls, *args,**kwargs):
- print("new",cls)
- return object.__new__(cls, *args,**kwargs)
- a = A()
- 结果输出:
- new <class '__main__.A'>
- init <class '__main__.A'>
- 上面的类中定义了 init 和 new, 在创建实例对象 a 时, 代码执行只是经过了 init 的函数定义部分, 把这个函数名存在记忆当中, 需要用时再调用. 然后到了 new 方法时, 接受当前这个类给第一参数 cls, 来创建对象. 创建好对象之后, 这个对象的属性方法还什么都没有, 现在就返回这个对象 (也就是 init 中的 self), 来给 init 来初始化一些内容. 如果构造函数并没有返回这个类的对象, 那么 init 方法也就不会被调用. 这也符合了上面的输出结果, 先输出的 new 方法的内容, 后执行的 init 方法中的输出.
- 没有返回这个类的对象可以是根本就没有返回值, 也可能是返回的对象并不是当前的类的对象, 下面会对应举两个例子:
- 上面这张截图中, 我把上面代码的 new 方法返回删掉了, 现在就只调用的 new 方法, 而没有到 init 方法内部去. 现在这种情况就是 new 没有返回对象, init 方法的第一参数 self 就没有接收到要初始化的对象, 因此并不执行.
- class A(object):
- """docstring for A"""
- pass
- class B(A):
- """docstring for B"Af __init__(self, arg): """
- def __init__(self):
- print("init",self.__class__)
- def __new__(cls):
- print("new",cls)
- return object.__new__(A) # 返回的是 A 的对象, 并不是当前类中的实例对象, 所以不能调用 init 方法
上面这段代码是说构造函数有返回值, 但不是当前类的实例对象, 因此也不能调用初始化方法.
来源: https://www.cnblogs.com/yudanqu/p/9240237.html