[Python] Python 之 __new__() 方法与实例化

__new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() 启动之前,__new__() 决定是否要使用该 __init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。

如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而__new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。

__new__() 方法的特性:

  • __new__() 方法是在类准备将自身实例化时调用。
  • __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
  • 类的实例化和它的构造方法通常都是这个样子:
class MyClass(object):def __init__(self, *args, **kwargs):...# 实例化
myclass = MyClass(*args, **kwargs)

  

正如以上所示,一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 __init__() 方法之前,Python 首先调用 __new__() 方法:

def __new__(cls, *args, **kwargs):...

  

第一个参数cls是当前正在实例化的类。

  • 如果要得到当前类的实例,应当在当前类中的 __new__() 方法语句中调用当前类的父类的 __new__() 方法。

  例如,如果当前类是直接继承自 object,那当前类的 __new__() 方法返回的对象应该为:

def __new__(cls, *args, **kwargs):...return object.__new__(cls)

  

注意:

  事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。

  而如果新式类中重写了__new__()方法,那么你可以自由选择任意一个的其他的新式类(必定要是新式类,只有新式类必定都有__new__(),因为所有新式类都是object的后代,而经典类则没有__new__()方法)的__new__()方法来制造实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。具体看以下代码解释:

class Foo(object):def __init__(self, *args, **kwargs):...def __new__(cls, *args, **kwargs):return object.__new__(cls, *args, **kwargs)    

# 以上return等同于 # return object.__new__(Foo, *args, **kwargs)# return Stranger.__new__(cls, *args, **kwargs)# return Child.__new__(cls, *args, **kwargs)
class Child(Foo):def __new__(cls, *args, **kwargs):return object.__new__(cls, *args, **kwargs)
# 如果Child中没有定义__new__()方法,那么会自动调用其父类的__new__()方法来制造实例,即 Foo.__new__(cls, *args, **kwargs)。# 在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环。因此必须避免类似以下的写法:# 在Foo中避免:return Foo.__new__(cls, *args, **kwargs)或return cls.__new__(cls, *args, **kwargs)。Child同理。# 使用object或者没有血缘关系的新式类的__new__()是安全的,但是如果是在有继承关系的两个类之间,应避免互调造成死循环,例如:(Foo)return Child.__new__(cls), (Child)return Foo.__new__(cls)。
class Stranger(object):...# 在制造Stranger实例时,会自动调用 object.__new__(cls)

  •  通常来说,新式类开始实例化时,__new__()方法会返回cls(cls指代当前类)的实例,然后该类的__init__()方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入__new__()方法中接收的位置参数和命名参数。

注意:如果__new__()没有返回cls(即当前类)的实例,那么当前类的__init__()方法是不会被调用的。如果__new__()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方法。

class Foo(object):def __init__(self, *args, **kwargs):...def __new__(cls, *args, **kwargs):return object.__new__(Stranger, *args, **kwargs)  class Stranger(object):...foo = Foo()
print type(foo)    

# 打印的结果显示foo其实是Stranger类的实例。

# 因此可以这么描述__new__()和__ini__()的区别,在新式类中__new__()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__()使其丰满。# 如果以建房子做比喻,__new__()方法负责开发地皮,打下地基,并将原料存放在工地。而__init__()方法负责从工地取材料建造出地皮开发招标书中规定的大楼,__init__()负责大楼的细节设计,建造,装修使其可交付给客户。

转载于:https://www.cnblogs.com/TF511/p/10039159.html

面向对象—的__new__()方法详解相关推荐

  1. JavaSE——面向对象进阶(封装、this、static、代码块、包、权限修饰符、main方法详解)

    第2节 面向对象进阶 一.封装与private 概述: 封装的意义在于保护或者防止代码(数据)被我们无意中破坏.保护成员属性,不让类以外的程序直接访问和修改. 封装原则: 隐藏对象的属性和实现细节,仅 ...

  2. php中this的使用技巧,JavaScript中this关键字使用方法详解

    JavaScript中this关键字使用方法详解 在面向对象编程语言中,对于this关键字我们是非常熟悉的.比如C++.C#和Java等都提供了这个关键字,虽然在开始学习的时候觉得比较难,但只要理解了 ...

  3. python怎样实现封装_Python底层封装实现方法详解

    Python底层封装实现方法详解 这篇文章主要介绍了Python底层封装实现方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 事实上,pyth ...

  4. C# 面向对象编程【多态详解】

    C# 面向对象编程[多态详解] 文章目录 C# 面向对象编程[多态详解] 1. 里氏转换 2. 多态 2.1 虚方法 3.2 抽象类 3.3 接口 1. 里氏转换 1).子类可以赋值给父类 2).如果 ...

  5. PHP之十六个魔术方法详解 转自:青叶

    目录 PHP之十六个魔术方法详解 前言 范例 〇.__serialize() 和 __unserialize() 一. __construct(),类的构造函数 二.__destruct(),类的析构 ...

  6. python统计csv行数_对Python 多线程统计所有csv文件的行数方法详解

    如下所示: #统计某文件夹下的所有csv文件的行数(多线程) import threading import csv import os class MyThreadLine(threading.Th ...

  7. python修改文件内容_Python批量修改文本文件内容的方法详解

    这篇文章主要介绍了Python批量修改文本文件内容的方法的相关资料,需要的朋友可以参考下 Python批量替换文件内容,支持嵌套文件夹 import os path="./" fo ...

  8. python二维元组_python中读入二维csv格式的表格方法详解(以元组/列表形式表示)

    如何去读取一个没有表头的二维csv文件(如下图所示)? 并以元组的形式表现数据: ((1.0, 0.0, 3.0, 180.0), (2.0, 0.0, 2.0, 180.0), (3.0, 0.0, ...

  9. Spring JdbcTemplate方法详解

    2019独角兽企业重金招聘Python工程师标准>>> Spring JdbcTemplate方法详解 标签: springhsqldbjava存储数据库相关sql 2012-07- ...

最新文章

  1. 2、使用rpm包安装grafana
  2. 【转】How Many Boyfriends
  3. Spring的lazy-init详解
  4. c语言对分查找实验报告,C语言实验指导.doc
  5. hashmap中的hash扰动函数
  6. PropertySource和ConfigurationProperties
  7. 如何维持手机电池寿命_手机电池不耐用,都怪这些充电坏毛病
  8. 一些Layout的坑
  9. web淘宝电商页面搭建
  10. 详细剖析二进制文件的读写
  11. matlab编写多目标性能度量r、GD、Spacing、德尔塔
  12. 【LSSVM回归预测】基于matlab人工蜂群算法优化最小二乘支持向量机LSSVM数据回归预测【含Matlab源码 2213期】
  13. Python_小林的爬取QQ空间相册图片链接程序
  14. 致刚入职场的你 - 程序员的成长笔记
  15. wangeditor 两个editor失焦解决办法
  16. 多目标跟踪之匈牙利算法
  17. tcp欢动窗口机制_TCP 滑动窗口(发送窗口和接收窗口)
  18. Python网络爬虫与信息提取笔记08-实例2:淘宝商品比价定向爬虫
  19. matlab里knapsack_tad,knapsack-problem
  20. 新手摆摊进来看看(明确卖什么很关键)

热门文章

  1. 【LeetCode-SQL每日一练】—— 196. 删除重复的电子邮箱
  2. Navicat15安装笔记
  3. 【HDU - 5876】Sparse Graph(补图bfs,STLset)
  4. 【POJ - 3160】Father Christmas flymouse(Tarjan缩点,DAG最长路)
  5. 【Codeforces - 632C】The Smallest String Concatenation (对string巧妙排序)
  6. android volley 上传图片 和参数,Android使用Volley上传文件
  7. android 怎么获取app 字体颜色,android app 修改字体
  8. linux+last命令菜鸟,Linux基本命令。。。菜鸟保留
  9. c语言常用算法累加法例题,C语言第三次模拟练习题部分解答.docx
  10. 限制在同一台电脑上只允许有一个用户登录系统