Python类的__new__()

 

  本篇主要想要详细的介绍一下关于类的魔法方法__new__()方法。

  在学习之前我们看一下Python3中关于object基类的__new__() 方法:

    @staticmethod # known case of __new__
    def __new__(cls, *more): # known special case of object.__new__
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

  上述描述:__new__()创建和返回一个新的对象。通俗说:该魔法属性是用来创建实例对象的。接下来我们看一下它的是如何创建对象的。

一、理解

  1、__new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前。

  即可以这样理解:Python中存在于类中的构造方法__init__()负责将类实例化,而在__init__()执行之前,__new__()负责制造这样的一个实例对象,以便__init__()去让该实例对象更加的丰富(为其添加属性等)。

  同时:__new__() 方法还决定是否要使用该__init__() 方法,因为__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。

  2、__new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。

    比喻

  

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

  

二、结构

  在Python中,若不重写类中的__new__()方法,其默认的结构时这样的:

class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return super().__new__(cls,*args,**kwagrs)

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

  如果要得到当前类的实例,应当在当前类中的__new__()方法语句中调用当前类的父类 的__new__()方法。例如,如果当前类是直接继承自object,那当前类的__new__()方法返回的对象应该为:
class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return object.__new__(cls,*args,**kwagrs)

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

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

class A(object):
    pass

class B(A):
    pass

class C(B):
    def __new__(cls,*args,**kwargs):
        return super().__new__(cls, *args,**kwargs)

        # 等同于:
        # return B.__new__(cls, *args,**kwargs)
        # return A.__new__(cls, *args,**kwargs)
        # return object.__new__(cls, *args,**kwargs)

  2、在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环。

  例如:

class Bar(object):
    def __new__(cls,*agrs,**kwagrs):
        return Bar.__new__(Foo,*agrs,**kwagrs)

  这样的话会造成 当Bar调用其自身的__new__() 方法制造实例时,又会跳到第二行去执行__new__(),当到第三行时,又跳到第二行去调用__new__(),这样不断的就会陷入死循环。

  3、Bar.__new__(Foo,*agrs,**kwagrs) ,指:使用哪个类(bar)的__new__()方法去制造谁的(Foo)实例对象。

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

  注:如果__new__()没有返回cls(即当前类)的实例,那么当前类的__init__()方法是不会被调用 的。如果__new__()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方 法。
class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return object.__new__(cls,*args,**kwagrs)
    
    def __init__(self,name):
        self.name = name

class Bar(object):
    def __new__(cls,*agrs,**kwagrs):
        return object.__new__(Foo,*agrs,**kwagrs)
    
bar = Bar()
print(type(bar)) #foo其实是Stranger类的实例。

# 输出为:<class '__main__.Foo'>

   会发现上例:制造的是Foo的实例对象。

 

  总结:因此可以这么描述__new__()和__ini__()的区别,在新式类中__new__()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__()使其丰满。

    如果以建房子做比喻,__new__()方法负责开发地皮,打下地基,并将原料存放在工地。而__init__()方法负责从工地取材料建造出地皮开发招标书中规定的大楼,__init__()负责大楼的细节设计,建造,装修使其可交付给客户。

 

posted @ 2018-09-21 22:13  Little_five  阅读(8161)  评论(0编辑  收藏  举报