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 开发者节省时间的10个方法
Oct 02 Python
用python做一个搜索引擎(Pylucene)的实例代码
Jul 05 Python
Python数据分析之双色球统计两个红和蓝球哪组合比例高的方法
Feb 03 Python
python3.x实现发送邮件功能
May 22 Python
替换python字典中的key值方法
Jul 06 Python
Python分割指定页数的pdf文件方法
Oct 26 Python
python 获取键盘输入,同时有超时的功能示例
Nov 13 Python
用python的turtle模块实现给女票画个小心心
Nov 23 Python
使用python+whoosh实现全文检索
Dec 09 Python
python爬虫开发之Beautiful Soup模块从安装到详细使用方法与实例
Mar 09 Python
opencv+pyQt5实现图片阈值编辑器/寻色块阈值利器
Nov 13 Python
教你如何用Python实现人脸识别(含源代码)
Jun 23 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学习笔记(三)操作符与控制结构
2011/08/06 PHP
php中使用sftp教程
2015/03/30 PHP
phpStudy配置多站点多域名方法及遇到的403错误解决方法
2017/10/19 PHP
Laravel框架实现定时发布任务的方法
2018/08/16 PHP
PHP登录验证功能示例【用户名、密码、验证码、数据库、已登陆验证、自动登录和注销登录等】
2019/02/25 PHP
laravel框架中间件简单使用方法示例
2020/01/25 PHP
jquery获取一组checkbox的值(实例代码)
2013/11/04 Javascript
Javascript实现获取及设置光标位置的方法
2015/07/21 Javascript
js实现显示当前状态的导航效果代码
2015/08/28 Javascript
JS实现三个层重叠点击互相切换的方法
2015/10/06 Javascript
javascript实现状态栏中文字动态显示的方法
2015/10/20 Javascript
jQuery过滤选择器经典应用
2016/08/18 Javascript
第一次动手实现bootstrap table分页效果
2016/09/22 Javascript
vue2.0嵌套路由实现豆瓣电影分页功能(附demo)
2017/03/13 Javascript
JavaScript校验Number(4,1)格式的数字实例代码
2017/03/13 Javascript
vue项目国际化vue-i18n的安装使用教程
2018/03/14 Javascript
微信小程序文字显示换行问题
2019/07/28 Javascript
浅谈Node新版本13.2.0正式支持ES Modules特性
2019/11/25 Javascript
three.js着色器材质的内置变量示例详解
2020/08/16 Javascript
python rsa 加密解密
2017/03/20 Python
Python之str操作方法(详解)
2017/06/19 Python
Python实现学生成绩管理系统
2020/04/05 Python
python系列 文件操作的代码
2019/10/06 Python
Python关于__name__属性的含义和作用详解
2020/02/19 Python
python如何写try语句
2020/07/14 Python
Python 使用 PyQt5 开发的关机小工具分享
2020/07/16 Python
用gpu训练好的神经网络,用tensorflow-cpu跑出错的原因及解决方案
2021/03/03 Python
HTML5等待加载动画效果
2017/07/27 HTML / CSS
迪卡侬(Decathlon)加拿大官网:源自法国的运动专业超市
2020/11/22 全球购物
捷克建筑材料网上商店:DEK.cz
2021/03/06 全球购物
Java程序员面试题
2013/07/15 面试题
六十岁生日答谢词
2014/01/10 职场文书
中学生运动会口号
2014/06/07 职场文书
2014年教师党员自我评价范文
2014/09/22 职场文书
加薪申请报告范本
2015/05/15 职场文书
85句关于理想的名言警句大全
2019/08/22 职场文书