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

参考了: http://www.cnblogs.com/ifantastic/p/3175735.html

Python 的 __new__()方法与实例化的更多相关文章

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

    __new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() ...

  2. Python 之 __new__() 方法与实例化

    原文链接:https://www.cnblogs.com/ifantastic/p/3175735.html __new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解, ...

  3. Python 之 __new__() 方法与实例化(转)

    _new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() ...

  4. 【python】Python 之 __new__() 方法与实例化

    本文转自:http://www.cnblogs.com/ifantastic/p/3175735.html __new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 ...

  5. Python中的__new__()方法与实例化

    @Python中的__new__()方法与实例化   __new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在Python 中 存在于类里面的构造方法__init__ ...

  6. 第8.8节 Python使用__new__方法和构造方法__init__完成类实例化的过程详解

    第8.8节 Python使用__new__方法和构造方法__init__完成类实例化的过程详解 前面章节介绍了Python类中的__new__方法和构造方法__init__,并通过实例分析了二者之间关 ...

  7. Python中__new__方法为什么有人说是构造方法?有什么作用?

    __new__方法是Python新式类引入的,通常用于控制生成一个新实例的过程.它是类级别的静态方法,是在创建实例对象前执行,如果自定义类中没有重写该方法,则Python自动调用父类的方法,当所有父类 ...

  8. python的__new__方法

    https://www.cnblogs.com/kex1n/p/5991249.html https://blog.csdn.net/wwx890208/article/details/8053445 ...

  9. [Python]python面向对象 __new__方法及单例设计

    __new__ 方法 使用 类名() 创建对象时,Python 的解释器 首先 会 调用 __new__ 方法为对象 分配空间 __new__ 是一个 由 object 基类提供的 内置的静态方法,主 ...

随机推荐

  1. POJ3020 Antenna Placement(二分图最小路径覆盖)

    The Global Aerial Research Centre has been allotted the task of building the fifth generation of mob ...

  2. 关于AJAX与JSON的杂记

    一.当网页需要有多个XMLHttpRequest对象时,可以使用Callback 函数,callback 函数是一种以参数形式传递给另一个函数的函数. <html> <head> ...

  3. Boosting and Its Application in LTR

    1 Boosting概述 2 Classification and Regression Tree 3 AdaBoost 3.1 算法框架 3.2 原理:Additive Modeling 4 Gra ...

  4. C# socket请求的名称有效 但是找不到请求的类型的数据

    程序以前在xp下运行一直良好,但将安装在win7下面却出现"请求的名称有效 但是找不到请求的类型的数据"错误,程序底层通信是基于socket,时间久了就会出现系统黑屏死机,但并不知 ...

  5. C# 读取Text文本,写入Text文本

    //读取 private void showMess() { this.dataGridViewX2.Rows.Clear(); //将车辆信息一行行添加到datagreatview 里面 Strea ...

  6. GetPixelAddress()函数Alpha通道会丢失

    CImage类中GetPixelAddress()函数来设置获取对应的颜色值是发现Alpha无效. void CGBImage::Load(){ CImage sourceImage; sourceI ...

  7. 51 nod 1350 斐波那契表示

    每一个正整数都可以表示为若干个斐波那契数的和,一个整数可能存在多种不同的表示方法,例如:14 = 13 + 1 = 8 + 5 + 1,其中13 + 1是最短的表示(只用了2个斐波那契数).定义F(n ...

  8. luoguP4172 [WC2006]水管局长

    https://www.luogu.org/problemnew/show/P4172 考虑倒序处理所有操作 先把不会被删掉的边加入图中,LCT 维护最小生成树,再倒序插入每一条边,如果边的 ( l, ...

  9. lamp centos下一键安装

    系统需求 系统支持:CentOS 6+/Debian 7+/Ubuntu 12+ 内存要求:≥ 512MB 硬盘要求:至少 5GB 以上的剩余空间 服务器必须配置好 软件源 和 可连接外网 必须具有系 ...

  10. 百度编辑器 Ueditor使用记录

    Ueditor官网: http://fex.baidu.com/ueditor/#dev-bale_width_grunt UeditorAPI文档: https://ueditor.baidu.co ...