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读取ini文件、操作mysql、发送邮件实例
Jan 01 Python
详解duck typing鸭子类型程序设计与Python的实现示例
Jun 03 Python
Python之日期与时间处理模块(date和datetime)
Feb 16 Python
Python设计模式之门面模式简单示例
Jan 09 Python
基于Django用户认证系统详解
Feb 21 Python
简单了解python变量的作用域
Jul 30 Python
pytorch 可视化feature map的示例代码
Aug 20 Python
django ajax发送post请求的两种方法
Jan 05 Python
Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法
May 26 Python
python打包生成so文件的实现
Oct 30 Python
python爬虫用request库处理cookie的实例讲解
Feb 20 Python
Python可视化学习之seaborn绘制矩阵图详解
Feb 24 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 date()日期时间函数详解
2010/05/16 PHP
php通过COM类调用组件的实现代码
2012/01/11 PHP
php调用方法mssql_fetch_row、mssql_fetch_array、mssql_fetch_assoc和mssql_fetch_objcect读取数据的区别
2012/08/08 PHP
Yii结合CKEditor实现图片上传功能
2014/06/13 PHP
优化WordPress的Google字体以加速国内服务器上的运行
2015/11/24 PHP
PHP实现基于面向对象的mysqli扩展库增删改查操作工具类
2017/07/18 PHP
yii2多图上传组件的使用教程
2018/05/10 PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
2020/02/27 PHP
javascript 实现父窗口引用弹出窗口的值的脚本
2007/08/07 Javascript
javascript+xml技术实现分页浏览
2008/07/27 Javascript
JS使用parseInt解析数字实现求和的方法
2015/08/05 Javascript
jQuery+css3实现转动的正方形效果(附demo源码下载)
2016/01/27 Javascript
浅析JavaScript 箭头函数 generator Date JSON
2016/05/23 Javascript
浅析JSONP技术原理及实现
2016/06/08 Javascript
JS实现的图片选择顺序切换和循环切换功能示例【测试可用】
2018/12/28 Javascript
Node.js操作系统OS模块用法分析
2019/01/04 Javascript
JavaScript怎样在删除前添加确认弹出框?
2019/05/27 Javascript
JS使用new操作符创建对象的方法分析
2019/05/30 Javascript
[07:31]DOTA2卡尔工作室 英雄介绍主宰篇
2013/06/25 DOTA
pandas DataFrame 删除重复的行的实现方法
2019/01/29 Python
django中media媒体路径设置的步骤
2019/11/15 Python
CSS3不透明度实例讲解
2016/04/26 HTML / CSS
澳大利亚小众服装品牌:Maurie & Eve
2018/03/27 全球购物
巴黎卡诗加拿大官网:Kérastase加拿大
2018/11/12 全球购物
AP澳洲中文网:澳洲正品直邮,包税收件无忧
2019/07/12 全球购物
高级运动鞋:GREATS
2019/07/19 全球购物
小组合作学习反思
2014/02/18 职场文书
幼儿园秋季开学寄语
2014/08/02 职场文书
2014年党员干部四风问题自我剖析材料
2014/09/29 职场文书
个人四风问题对照检查材料思想汇报
2014/10/06 职场文书
放射科岗位职责
2015/02/14 职场文书
给朋友的道歉短信
2015/05/12 职场文书
阿里云 Windows server 2019 配置FTP
2022/04/28 Servers
Hive常用日期格式转换语法
2022/06/25 数据库
spring 项目实现限流方法示例
2022/07/15 Java/Android
win10系统计算机图标怎么调出来?win10调出计算机图标的方法
2022/08/14 数码科技