Python中__new__与__init__方法的区别详解

在python2.x中,从object继承得来的类称为新式类(如class A(object))不从object继承得来的类称为经典类(如class A())python

新式类跟经典类的差异主要是如下几点:编程

  1. 新式类对象能够直接经过__class__属性获取自身类型:type函数

  2. 继承搜索的顺序发生了改变,经典类多继承时属性搜索顺序: 先深刻继承树左侧,再返回,开始找右侧(即深度优先搜索);新式类多继承属性搜索顺序: 先水平搜索,而后再向上移动code

例子:对象

经典类: 搜索顺序是(D,B,A,C)继承

>>> class A: attr = 1
...
>>> class B(A): pass
...
>>> class C(A): attr = 2
...
>>> class D(B,C): pass
...
>>> x = D()
>>> x.attr
1


新式类继承搜索程序是宽度优先get

新式类:搜索顺序是(D,B,C,A)it

>>> class A(object): attr = 1
...
>>> class B(A): pass
...
>>> class C(A): attr = 2
...
>>> class D(B,C): pass
...
>>> x = D()
>>> x.attr
2

  3. 新式类增长了__slots__内置属性, 能够把实例属性的种类锁定到__slots__规定的范围之中。class

  4. 新式类增长了__getattribute__方法object

  5.新式类内置有__new__方法而经典类没有__new__方法而只有__init__方法

注意:Python 2.x中默认都是经典类,只有显式继承了object才是新式类

     而Python 3.x中默认都是新式类(也即object类默认是全部类的祖先),没必要显式的继承object(能够按照经典类的定义方式写一个经典类并分别在python2.x和3.x版本中使用dir函数检验下。

例如:

class A():
    pass
 
print(dir(A))


会发如今2.x下没有__new__方法而3.x下有。

接下来讲下__new__方法和__init__的区别:

在python中建立类的一个实例时,若是该类具备__new__方法,会先调用__new__方法,__new__方法接受当前正在实例化的类做为第一个参数(这个参数的类型是type,这个类型在c和python的交互编程中具备重要的角色,感兴趣的能够搜下相关的资料),其返回值是本次建立产生的实例,也就是咱们熟知的__init__方法中的第一个参数self。那么就会有一个问题,这个实例怎么获得?

注意到有__new__方法的都是object类的后代,所以若是咱们本身想要改写__new__方法(注意不改写时在建立实例的时候使用的是父类的__new__方法,若是父类没有则继续上溯)能够经过调用object的__new__方法类获得这个实例(这实际上也和python中的默认机制基本一致),如:

class display(object):
  def __init__(self, *args, **kwargs):
    print("init")
  def __new__(cls, *args, **kwargs):
    print("new")
    print(type(cls))
    return object.__new__(cls, *args, **kwargs)  
a=display()

运行上述代码会获得以下输出:

new
 
<class 'type'>
 
init

所以咱们能够获得以下结论:

在实例建立过程当中__new__方法先于__init__方法被调用,它的第一个参数类型为type。

若是不须要其它特殊的处理,可使用object的__new__方法来获得建立的实例(也即self)。

因而咱们能够发现,实际上可使用其它类的__new__方法类获得这个实例,只要那个类或其父类或祖先有__new__方法。

class another(object):
  def __new__(cls,*args,**kwargs):
    print("newano")
    return object.__new__(cls, *args, **kwargs)  
class display(object):
  def __init__(self, *args, **kwargs):
    print("init")
  def __new__(cls, *args, **kwargs):
    print("newdis")
    print(type(cls))
    return another.__new__(cls, *args, **kwargs)  
a=display()

上面的输出是:

newdis
<class 'type'>
newano
init

全部咱们发现__new__和__init__就像这么一个关系,__new__提供生产的原料self(但并不保证这个原料来源正宗,像上面那样它用的是另外一个不相关的类的__new__方法类获得这个实例),而__init__就用__new__给的原料来完善这个对象(尽管它不知道这些原料是否是正宗的)

相关文章
相关标签/搜索