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


Posted in Python onMay 04, 2015

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

新式类跟经典类的差别主要是以下几点:

1. 新式类对象可以直接通过__class__属性获取自身类型:type

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

例子:

经典类: 搜索顺序是(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

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

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

>>> 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__规定的范围之中。

4. 新式类增加了__getattribute__方法

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__就像这么一个关系,__init__提供生产的原料self(但并不保证这个原料来源正宗,像上面那样它用的是另一个不相关的类的__new__方法类得到这个实例),而__init__就用__new__给的原料来完善这个对象(尽管它不知道这些原料是不是正宗的)

Python 相关文章推荐
对Python 多线程统计所有csv文件的行数方法详解
Feb 12 Python
详解重置Django migration的常见方式
Feb 15 Python
将pip源更换到国内镜像的详细步骤
Apr 07 Python
深入浅析python 协程与go协程的区别
May 09 Python
django框架用户权限中的session缓存到redis中的方法
Aug 06 Python
基于Python和PyYAML读取yaml配置文件数据
Jan 13 Python
基于pycharm实现批量修改变量名
Jun 02 Python
PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步骤详解
Nov 02 Python
pytorch 带batch的tensor类型图像显示操作
May 20 Python
判断Python中的Nonetype类型
May 25 Python
这样写python注释让代码更加的优雅
Jun 02 Python
Python中的 Set 与 dict
Mar 13 Python
Python中的ConfigParser模块使用详解
May 04 #Python
Python的__builtin__模块中的一些要点知识
May 02 #Python
一些Python中的二维数组的操作方法
May 02 #Python
在Python的Tornado框架中实现简单的在线代理的教程
May 02 #Python
探究Python的Tornado框架对子域名和泛域名的支持
May 02 #Python
Python编程中运用闭包时所需要注意的一些地方
May 02 #Python
按日期打印Python的Tornado框架中的日志的方法
May 02 #Python
You might like
php小技巧之过滤ascii控制字符
2014/05/14 PHP
php函数与传递参数实例分析
2014/11/15 PHP
php中简单的对称加密算法实现
2017/01/05 PHP
TNC vs BOOM BO3 第一场2.13
2021/03/10 DOTA
超清晰的document对象详解
2007/02/27 Javascript
JQuery小知识
2010/10/15 Javascript
JavaScript NaN和Infinity特殊值 [译]
2012/09/20 Javascript
JS 屏蔽按键效果与改变按键效果的示例代码
2013/12/24 Javascript
防止jQuery ajax Load使用缓存的方法小结
2014/02/22 Javascript
jquery禁用右键示例
2014/04/28 Javascript
深入分析下javascript中的[]()+!
2015/07/07 Javascript
全面解析Bootstrap手风琴效果
2020/04/17 Javascript
基于Node.js的JavaScript项目构建工具gulp的使用教程
2016/05/20 Javascript
React Native预设占位placeholder的使用
2017/09/28 Javascript
vue实现的下拉框功能示例
2019/01/29 Javascript
在Layui 的表格模板中,实现layer父页面和子页面传值交互的方法
2019/09/10 Javascript
微信小程序修改数组长度的问题的解决
2019/12/17 Javascript
基于vue和bootstrap实现简单留言板功能
2020/05/30 Javascript
为python设置socket代理的方法
2015/01/14 Python
30分钟搭建Python的Flask框架并在上面编写第一个应用
2015/03/30 Python
自己使用总结Python程序代码片段
2015/06/02 Python
python爬虫之urllib,伪装,超时设置,异常处理的方法
2018/12/19 Python
django的settings中设置中文支持的实现
2019/04/28 Python
Python中使用__new__实现单例模式并解析
2019/06/25 Python
Numpy 理解ndarray对象的示例代码
2020/04/03 Python
python为什么要安装到c盘
2020/07/20 Python
CSS3 calc()会计算属性详解
2018/02/27 HTML / CSS
HTML5实现获取地理位置信息并定位功能
2015/04/25 HTML / CSS
网络、C以及其他硬件方面的面试题
2016/08/23 面试题
如何在存储过程中使用Loop
2016/01/05 面试题
综合素质的自我鉴定
2013/10/07 职场文书
运动会通讯稿50字
2014/01/30 职场文书
法学专业毕业生自荐信
2014/06/11 职场文书
2019年大学生职业生涯规划书最新范文
2019/03/25 职场文书
Javascript之datagrid查询详解
2021/09/15 Javascript
以MySQL5.7为例了解一下执行计划
2022/04/13 MySQL