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通过floor函数舍弃小数位的方法
Mar 17 Python
python中函数传参详解
Jul 03 Python
python调用tcpdump抓包过滤的方法
Jul 18 Python
解决python 无法加载downsample模型的问题
Oct 25 Python
python 画三维图像 曲面图和散点图的示例
Dec 29 Python
python实现抽奖小程序
Apr 15 Python
在PyCharm的 Terminal(终端)切换Python版本的方法
Aug 02 Python
python:目标检测模型预测准确度计算方式(基于IoU)
Jan 18 Python
python GUI库图形界面开发之PyQt5状态栏控件QStatusBar详细使用方法实例
Feb 28 Python
python实现ftp文件传输系统(案例分析)
Mar 20 Python
Jupyter加载文件的实现方法
Apr 14 Python
Python实现读取并写入Excel文件过程解析
May 27 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 文件夹删除、php清除缓存程序
2009/08/25 PHP
基于php split()函数的用法详解
2013/06/05 PHP
laravel 4安装及入门图文教程
2014/10/29 PHP
php中字符查找函数strpos、strrchr与strpbrk用法
2014/11/18 PHP
PHP根据session与cookie用户登录状态操作类的代码
2016/05/13 PHP
看了就知道什么是JSON
2007/12/09 Javascript
关于IE、Firefox、Opera页面呈现异同 写脚本很痛苦
2009/08/28 Javascript
让mayfish支持mysqli数据库驱动的实现方法
2010/05/22 Javascript
精心挑选的12款优秀的基于jQuery的手风琴效果插件和教程
2012/08/22 Javascript
JS实现获取键盘按下的按键并显示在页面上的方法
2015/11/04 Javascript
史上最全JavaScript数组去重的十种方法(推荐)
2017/08/17 Javascript
webpack多入口多出口的实现方法
2018/08/17 Javascript
Vue父子组件之间的通信实例详解
2018/09/28 Javascript
微信小程序云开发详细教程
2019/05/16 Javascript
深入学习Vue nextTick的用法及原理
2019/10/08 Javascript
微信小程序使用 vant Dialog组件的正确方式
2020/02/21 Javascript
深入解析Python中的线程同步方法
2016/06/14 Python
基于python 二维数组及画图的实例详解
2018/04/03 Python
浅谈python新式类和旧式类区别
2019/04/26 Python
用Python+OpenCV对比图像质量的几种方法
2019/07/15 Python
selenium2.0中常用的python函数汇总
2019/08/05 Python
Django项目创建到启动详解(最全最详细)
2019/09/07 Python
python编写计算器功能
2019/10/25 Python
python ubplot使用方法解析
2020/01/10 Python
解决python 虚拟环境删除包无法加载的问题
2020/07/13 Python
python中加背景音乐如何操作
2020/07/19 Python
巴西宠物商店:Cobasi
2019/04/19 全球购物
东方通信股份有限公司VC面试题
2014/08/27 面试题
2013届毕业生求职信范文
2013/11/20 职场文书
干部行政关系介绍信
2014/01/17 职场文书
幼儿教师寄语集锦
2014/04/03 职场文书
趵突泉导游词
2015/02/03 职场文书
启迪人心的励志语录:脾气永远不要大于本事
2020/01/02 职场文书
两行代码解决Jupyter Notebook中文不能显示的问题
2021/04/24 Python
MySQL实例精讲单行函数以及字符数学日期流程控制
2021/10/15 MySQL
Vue OpenLayer 为地图绘制风场效果
2022/04/24 Vue.js