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的gevent框架的入门教程
Apr 29 Python
Python+django实现文件上传
Jan 17 Python
python实现的正则表达式功能入门教程【经典】
Jun 05 Python
Python数字图像处理之霍夫线变换实现详解
Jan 12 Python
opencv python 傅里叶变换的使用
Jul 21 Python
Python中那些 Pythonic的写法详解
Jul 02 Python
django之对FileField字段的upload_to的设定方法
Jul 28 Python
Python多叉树的构造及取出节点数据(treelib)的方法
Aug 09 Python
Laravel框架表单验证格式化输出的方法
Sep 25 Python
softmax及python实现过程解析
Sep 30 Python
python实现串口通信的示例代码
Feb 10 Python
python os.listdir()乱码解决方案
Jan 31 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 杂谈《重构-改善既有代码的设计》之三 重新组织数据
2012/04/09 PHP
PHP中字符安全过滤函数使用小结
2015/02/25 PHP
dojo 之基础篇(三)之向服务器发送数据
2007/03/24 Javascript
ExtJS 2.0 实用简明教程之布局概述
2009/04/29 Javascript
js 实现打印网页中定义的部分内容的代码
2010/04/01 Javascript
将list转换为json失败的原因
2013/12/17 Javascript
JavaScript实现基于Cookie的存储类实例
2015/04/10 Javascript
浅谈Sizzle的“编译原理”
2015/04/14 Javascript
分步解析JavaScript实现tab选项卡自动切换功能
2016/01/25 Javascript
jquery ztree实现树的搜索功能
2016/02/25 Javascript
移动端H5开发 Turn.js实现很棒的翻书效果
2016/06/20 Javascript
JavaScript交换两个变量值的七种解决方案
2016/12/01 Javascript
JavaScript实现Fly Bird小游戏
2016/12/15 Javascript
jQuery dateRangePicker插件使用方法详解
2017/07/28 jQuery
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
JsChart组件使用详解
2018/03/04 Javascript
vue-auto-focus: 控制自动聚焦行为的 vue 指令方法
2018/08/25 Javascript
vscode配置vue下的es6规范自动格式化详解
2019/03/20 Javascript
python3.6连接MySQL和表的创建与删除实例代码
2017/12/28 Python
python画出三角形外接圆和内切圆的方法
2018/01/25 Python
python微信跳一跳游戏辅助代码解析
2018/01/29 Python
Python 学习教程之networkx
2019/04/15 Python
Python 字符串、列表、元组的截取与切片操作示例
2019/09/17 Python
python GUI库图形界面开发之PyQt5窗口布局控件QStackedWidget详细使用方法
2020/02/27 Python
浅析两列自适应布局的3种思路
2016/05/03 HTML / CSS
NFL Game Pass欧洲:在线观看NFL比赛直播和点播,以高清质量播放
2018/08/30 全球购物
宝拉珍选英国官网:Paula’s Choice英国
2019/05/29 全球购物
Calphalon美国官网:美国顶级锅具品牌
2020/02/05 全球购物
.TTL是什么?有什么用处,通常那些工具会用到它?(ping? traceroute? ifconfig? netstat?)
2016/05/09 面试题
Unix如何在一行中运行多个命令
2015/05/29 面试题
简单而又朴实的个人求职信分享
2013/12/12 职场文书
保护环境倡议书100字
2014/05/19 职场文书
会计试用期自我评价怎么写
2014/09/18 职场文书
2014年党的群众路线学习心得体会
2014/11/05 职场文书
黄河绝恋观后感
2015/06/08 职场文书
2016秋季校长开学典礼致辞
2015/11/26 职场文书