__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__()负责大楼的细节设计,建造,装修使其可交付给客户。

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

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

    @Python中的__new__()方法与实例化   __new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在Python 中 存在于类里面的构造方法__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__()方法与实例化

    __new__() 是新式类中才有的方法,它执行在构造方法创建实例之前.可以这么理解,在 Python 中类中的构造方法 __init__() 负责将类实例化,而在 __init__() 启动之前,_ ...

  6. Python中的__new__()方法的使用

    __new__() 函数只能用于从object继承的新式类. 先看下object类中对__new__()方法的定义: class object:   @staticmethod # known cas ...

  7. 关于python中的__new__方法

    在上篇中,简单的比较了下new方法和init方法,然后结合网上的东西看了一点,发现..看书有的时候说的并不全面. __new__方法是一个类方法,主要作用是来指导如何生成类的实例, 主要用于,当需要生 ...

  8. python 中的__new__方法

    1.有关__new__方法的介绍 __new__方法调用在构造方法构造实例之前,即在__init__方法执行之前,我们可以这样理解,他的作用是决定是否适用这个__iint__方法来构造实例,但是需要注 ...

  9. 通俗的讲解Python中的__new__()方法

    2020-3-17更新本文,对本文中存争议的例子进行了更新! 曾经我幼稚的以为认识了python的__init__()方法就相当于认识了类构造器,结果,__new__()方法突然出现在我眼前,让我突然 ...

随机推荐

  1. Java 数据类型和变量

    1.1 基本类型与引用类型的区别 1.基本类型代表简单的数据类型,比如整数和字符,引用类型所引用的实例能表示任意一种复杂的数据类型. 2.基本类型仅表示数据类型,而引用类型所引用的实例除了表示复杂数据 ...

  2. 如何在.net4.0中使用.net4.5的async/await

    推荐文章: http://www.cnblogs.com/hj4444/p/3857771.html http://www.cnblogs.com/dozer/archive/2012/03/06/a ...

  3. performSelector:withObject:afterDelay: 精要概览(持续更新)

    - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay; - ...

  4. 《认识你自己(Archetypes who are you?)》 10种原型的行为模式和性格特征

    转自:http://www.cnblogs.com/richardcuick/p/5627298.html 拥护型原型   你自然而然地就会被社会.政治和环境问题所吸引. 你认为世界需要改变. 你承诺 ...

  5. QuickFIX/J常见问题汇总

    最近在搞QuickFIX/J,网上的资料不算很多,遇到一些简单的问题都需要google一阵才能找到解决方法,因此做点记录: 错误:Rejecting invalid message: quickfix ...

  6. CodeForces 166E -Tetrahedron解题报告

    这是本人写的第一次博客,学了半年的基础C语言,初学算法,若有错误还请指正. 题目链接:http://codeforces.com/contest/166/problem/E E. Tetrahedro ...

  7. 深入探索Android中的Handler

    一.概述 1. 什么是Handler Handler是Android消息机制的上层接口,它为我们封装了许多底层的细节,让我们能够很方便的使用底层的消息机制.Handler的最常见应用场景之一便是通过H ...

  8. Linux下线程池的理解与简单实现

    首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...

  9. PHP+微信分享自定义小图标

    微信分享以后的小图标如下图: <script>document.addEventListener('WeixinJSBridgeReady', function onBridgeReady ...

  10. js的__proto__与propertype的关系

    经典的再也不能经典的一篇博客:http://www.cnblogs.com/snandy/archive/2012/09/01/2664134.html js中最propertype的一些方法的理解h ...