python中__init__()方法和__new__()方法的区别

下面先通过一段代码看看这两个方法的调用顺序:

#!/usr/bin/env python

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'>

此处为什么会只输出一行,请参考文章[*Python中new()方法的使用和实例化]*(http://blog.csdn.net/four_infinite/article/details/52798919)

一般来说,”init”和”new”函数都会有下面的形式:

def __init__(self, *args, **kwargs):
    # func_suite

def __new__(cls, *args, **kwargs):
    # func_suite

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

重写_new_
如果(新式)类中没有重写”new”方法,Python默认是调用该类的直接父类的”new”方法来构造该类的实例,如果该类的父类也没有重写”new”,那么将一直按照同样的规则追溯至object的”new”方法,因为object是所有新式类的基类。

而如果新式类中重写了”new”方法,那么可以选择任意一个其他的新式类(必须是新式类,只有新式类有”new”,因为所有新式类都是从object派生)的”new”方法来创建实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。

看一段例子代码:

#!/usr/bin/env python
#coding:utf-8

class Foo(object):
    def __new__(cls,*args,**kwargs):
        obj = object.__new__(cls,*args,**kwargs)
        #这里的object.__new__(cls,*args,**kwargs)等价于
        # super(Foo,cls).__new__(cls,*args,**kwargs)
        # object.__new__(Foo,*args,**kwargs)
        # Bar.__new__(cls,*args,**kwargs)
        # Student.__new__(cls,*args,**kwargs),即使Student和
        # Foo没有关系也是允许的,因为Student是由object派生的新类
        # 在任何新式类中,不能调用自身的__new__来创建实例,因为这会
        # 造成死循环,所以要避免出现这样的语法 Foo.__new__(cls,*args,**kwargs)
        # 或者 cls.__new__(cls,*args,**kwargs)
        print "Calling __new__ for %s" % obj.__class__
        return obj

class Bar(Foo):
    def __new__(cls,*args,**kwargs):
        obj = object.__new__(cls,*args,**kwargs)
        print "Calling __new__ for %s" % obj.__class__
        return obj

class Student(object):
    #Student没有__new__方法,那么会自动调用父类的__new__方法来
    #创建实例,即会自动调用object.__new__(cls)
    pass

class Car(object):
    def __new__(cls,*args,**kwargs):
        obj = object.__new__(Bar,*args,**kwargs)
        print "Calling __new__ for %s" % obj.__class__
        return obj

foo = Foo()
bar = Bar()
car = Car()

运行结果是:

Calling __new__ for <class '__main__.Foo'>
Calling __new__ for <class '__main__.Bar'>
Calling __new__ for <class '__main__.Bar'>

_init_的调用

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

#!/usr/bin/env python

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)

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

运行结果是:

calling __new__ from <class '__main__.A'>
<class '__main__.A'>

派生不可变类型

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

#!/usr/bin/env python

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

f=Round2Float(4.324599)
print f

这段程序从float类中派生出了一个Round2Float类,这个类的作用就是保留小数点后两位的浮点数。

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值