new() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 init() 负责将类的实例化,而在 init() 启动之前,new() 决定是否要使用该 init() 方法,因为new() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。
如果将类比喻为工厂,那么init()方法则是该工厂的生产工人,init()方法接受的初始化参数则是生产所需原料,init()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而new()则是生产部经理,new()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 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)
网友评论