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

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

 

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

 

__new__() 方法的特性:spa

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

# 实例化
myclass = MyClass(*args, **kwargs)

  

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

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

  

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

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

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

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

  

注意:blog

  事实上若是(新式)类中没有重写__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__()负责大楼的细节设计,建造,装修使其可交付给客户。
相关文章
相关标签/搜索