python new和init知识点

每周学点土壤知识 2018-05-13

__new__ 方法是什么?
如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参 数则是生产所需原料,
__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 __new__()则是生产部经理,
__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,
因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
__new__方法是真正的创建实例的,决定了,该类能否创建实例
__new__()方法特性:
1.__new__()方法是在类准备将自身实例化时调用。
2.__new__()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。静态方法只有被类能够调用
一个类可以有多个位置参数和多个关键字参数,而在实例化开始之后,在调用 __init__()方法之前,Python首先调用__new__()方法:
def __new__(cls, *args, **kwargs):
...
如果要得到当前类的实例,应当在当前类中的__new__()方法语句中调用当前类的父类 的__new__()方法
例如,如果当前类是直接继承自object,那当前类的__new__()方法返回的对象应该为:
def __new__(cls, *args, **kwargs):
...
return object.__new__(cls)
(事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时 ,
Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写 __new__(),
那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。)
__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。

当你实例化一个类的时候,具体的执行逻辑是这样的:
p = Person(name, age)
首先使用name和age参数来执行Person类的__new__方法,这个__new__方法会 返回Person类的一个实例
(通常情况下是使用 super(Persion, cls).__new__(cls, ... ...) 这样的方式),
然后利用这个实例来调用类的__init__方法,上一步里面__new__产生的实例也就是 __init__里面的的 self
所以,__init__ 和 __new__ 最主要的区别在于:

__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

__new__ 的作用
依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple),
提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
在python中,真正创建实例的是__new__方法,这个方法是基于类的层面,__init__是实例创建出来之后,对类进行定制的,基于实例级别的

用__new__来实现单例模式
因为类每一次实例化产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。
===================
__new__() 函数只能用于从object继承的新式类
object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供
__new__()必须要有返回值,返回实例化出来的实例,需要注意的是,可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回

===================
例子1
class Demo(object):
def __init__(self):
print '__init__() called...'

def __new__(cls, *args, **kwargs):
print '__new__() - {cls}'.format(cls=cls)
return object.__new__(cls, *args, **kwargs)

if __name__ == '__main__':
de = Demo()

例子2
class Parent(object):
def __new__(cls):
print "Parent __new__ called"
return object.__new__(cls)
class Demo(Parent):
def __init__(self):
print "__init__ called"

def __new__(cls):
print "__new__ called"
return Parent.__new__(cls)

d= Demo()
输出:
__new__ called
Parent __new__ called
__init__ called

__new__方法是一级一级往上回溯走的,从父类最终到祖宗类object,也可以直接调用祖宗类object的__new__方法生成实例
发现实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法
__new__()必须要有返回值,返回实例化出来的实例,需要注意的是,可以return父类__new__()出来的实例,
也可以直接将object的__new__()出来的实例返回。
__init__()有一个参数self,该self参数就是__new__()返回的实例,__init__()在__new__()的基础上可以完成一些其它初始化的动作,
__init__()不需要返回值。
若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用,即使是父类的实例也不行。
我们可以将类比作制造商,__new__()方法就是前期的原材料购买环节,__init__()方法就是在有原材料的基础上,加工,初始化商品环节。
(这个类比比较好,new方法完以后,就出来了一个实例,可以认为这个实例还没有任何内容,空的,可以在这个阶段对这个类增加一些新属性,但是仅仅是对类
还不能对类实例操作,__init方法完以后,对这个实例进行了一些修饰,粉饰,这个阶段可以对类和实例,都进行属性的修改增加等操作)
类属性的访问,可以通过类或者实例,但是类属性的修改,只能通过类方式
默认的__new__方法会从子类开始一直调用父类的__new__方法,直到最后调用object的__new__方法。
但每次调用时传入的cls参数都是子类的类对象,所以最终能产生子类对象
===============
__new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在Python 中 存在于类里面的构造方法__init__()负责将类的实例化,
而在__init__()启动之前,__new__()决定是否 要使用该__init__()方法,
因为__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例

通常来说,新式类开始实例化时,__new__()方法会返回cls(cls指代当前类)的实例,
然后该类的 __init__()方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入__new__ ()方法中接收的位置参数和命名参数。
注意:如果__new__()没有返回cls(即当前类)的实例,那么当前类的__init__()方法是不会被调用 的。
如果__new__()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方 法。
================
在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环
使用object或者没有血缘关系的新式类的__new__()是安全的,但是如果是在有继承关系的两个类之间,应避免互调造成死循环
===============
因此可以这么描述__new__()和__ini__()的区别,在新式类中__new__()才是真正的实例化方法,为类

提供外壳制造出实例框架,然后调用该框架内的构造方法__init__()使其丰满。
# 如果以建房子做比喻,__new__()方法负责开发地皮,打下地基,并将原料存放在工地。而__init__()
方法负责从工地取材料建造出地皮开发招标书中规定的大楼,__init__()负责大楼的细节设计,建造,装修使其可交付给客户

相关推荐