python中init()方法和new()方法的区别

new()理解:

class A(object):
    def __init__(self,*args,**kwargs):
        print "init &&&&  %s" % self.__class__
    def __new__(cls,*args,**kwargs):
        print "new &&&&  %s" % cls
        return object.__new__(cls,*args,**kwargs)
a=A()
输出结果为:
new &&&&  <class '__main__.A'>
init &&&&  <class '__main__.A'>

如果把最后一行的return代码屏蔽掉,输出结果为:
new &&&&<class '__main__.A'>

new()是在新式类中新出现的方法,它作用在构造方法init()建造实例之前,可以这么理解,在Python 中存在于类里面的构造方法init()负责将类的实例化,而在init()调用之前,new()决定是否要使用该init()方法,因为new()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。

new()方法的特性:
new()方法是在类准备将自身实例化时调用。
new()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。

Python首先调用new()方法:

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

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()方法,那么你可以自由选择任意一个的其他的新式类(必定要是 新式类,只有新式类必定都有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)

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

如果Child中没有定义new()方法,那么会自动调用其父类的new()方法来制造实例,即

Foo.__new__(cls, *args, **kwargs)

使用object或者没有血缘关系的新式类的new()是安全的,但是如果是在有继承关系的两个类之间,应避免互调造成死循环,例如:(Foo)return Child.new(cls), (Child)return Foo.new(cls)。

关于”new”方法还有一个重要的用途就是用来派生不可变类型 。

例如,python中的float类型是一个不可变类型,如果想要从float中派生出一个子类,就可以使用”new”方法:

class Round2Float(float):
    def __new__(cls,num):
        num = round(num,2)
        obj = float.__new__(Round2Float,num)
        return obj

f=Round2Float(4.324599)
print f

init理解:

new”决定是否要使用该类的”init”方法,因为”new” 可以调用其他类的构造方法或者直接返回别的类创建的对象来作为本类的实例。
通常来说,新式类开始实例化时,”new”方法会返回cls(cls指代当前类)的实例,然后调用该类的”init”方法作为初始化方法,该方法接收这个实例(即self)作为自己的第一个参数,然后依次传入”new”方法中接收的位置参数和命名参数。
但是,如果”new”没有返回cls(即当前类)的实例,那么当前类的”init”方法是不会被调用的。例子:

class A(object):
    def __init__(self,*args,**kwargs):
        print "calling __init__ from %s" % self.__class__

    def __new__(cls,*args,**kwargs):
        obj = object.__new__(cls,*args,**kwargs)
        print "calling __new__ from %s" % obj.__class__
        return obj

class B(A):
    def __init__(self,*args,**kwargs):
        print "calling __init__ from %s" % self.__class__
    def __new__(cls,*args,**kwargs):
        obj = object.__new__(A,*args,**kwargs)
        print "calling __new__ from %s" % obj.__class__
        return obj

b=B()
print type(b)
结果是:
calling __new__ from <class '__main__.A'>
<class '__main__.A'>

代码中,在B的”new”方法中,通过”obj = object.new(A, *args, kwargs)”创建了一个A的实例,在这种情况下,B的”init”函数就不会被调用到。

区别:

对于”new”和”init”可以概括为:
new”方法在Python中是真正的构造方法(创建并返回实例),通过这个方法可以产生一个”cls”对应的实例对象,所以说”new”方法一定要有返回。
对于”init”方法,是一个初始化的方法,”self”代表由类产生出来的实例对象,”init”将对这个对象进行相应的初始化操作。

猜你喜欢

转载自blog.csdn.net/Lq_520/article/details/81712905