说说Python中的__new__和__init__的区别?

公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助!

小猿会从最基础的面试题开始,每天一题。如果参考答案不够好,或者有错误的话,麻烦大家可以在留言区给出自己的意见和讨论,大家是要一起学习的 。

废话不多说,开始今天的题目:

问:说说Python中的__new__和__init__的区别?

答:在Python中__new__和__init__具有不同的功能。并且对于Python的新类和旧类而言功能也不同。

__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法。

__init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候。是一个实例方法。

主要区别在于:__new__是用来创造一个类的实例的,而__init__是用来初始化一个实例的。

下文来源于:

https://www.jianshu.com/p/14b8ebf93b73

Python的新类和旧类

Python中的类分为新类和旧类。旧类是Python3之前的类,旧类并不是默认继承object类,而是继承type类。

Python2中的旧类如下面代码所示:

class oldStyleClass: # inherits from 'type'
    pass

Python2中定义一个新类:

class newStyleClass(object): # explicitly inherits from 'object'
    pass

在Python3中所有的类均默认继承object,所以并不需要显式地指定object为基类。

object为基类可以使得所定义的类具有新类所对应的方法(methods)和属性(properties)。

在下面的文章中我们会分别基于新类和旧类探讨__new____init__

__new____init__参数的不同

__new__所接收的第一个参数是cls,而__init__所接收的第一个参数是self。这是因为当我们调用__new__的时候,该类的实例还并不存在(也就是self所引用的对象还不存在),所以需要接收一个类作为参数,从而产生一个实例。而当我们调用__init__的时候,实例已经存在,因此__init__接受self作为第一个参数并对该实例进行必要的初始化操作。这也意味着__init__是在__new__之后被调用的。

Python旧类中的__new____init__

Python的旧类中实际上并没有__new__方法。因为旧类中的__init__实际上起构造器的作用。所以如果我们定义如下旧类:

class oldStyleClass:
    def __new__(cls):
        print("__new__ is called") # this line will never get called during construction

oldStyleClass()

程序输出结果如下:

<__main__.oldStyleClass instance at 0x109c45518>

可见创建及初始化对象的过程并没有调用__new__。实际上,除非显式调用:oldStyleClass.__new__(oldStyleClass),该类中的__new__方法中的内容永远不会被调用。因为旧类构造实例并不会调用__new__方法。

但如果我们重载__init__方法:

class oldStyleClass:
    def __init__(self):
        print("__init__ is called")

oldStyleClass()

该程序将会输出

__init__ is called
<__main__.oldStyleClass instance at 0x1091992d8>

如果我们在__init__中加上return语句,将会导致TypeError: __init__() should return None的错误。

class oldStyleClass:
    def __init__(self):
        return 29

oldStyleClass()

程序结果如下:

TypeError: __init__() should return None

这意味着对于Python的旧类而言,我们无法控制__init__函数的返回值。

Python新类中的__new____init__

Python的新类允许用户重载__new____init__方法,且这两个方法具有不同的作用。__new__作为构造器,起创建一个类实例的作用。而__init__作为初始化器,起初始化一个已被创建的实例的作用。

如下面代码是所示:

class newStyleClass(object): 
    # In Python2, we need to specify the object as the base.
    # In Python3 it's default.

    def __new__(cls):
        print("__new__ is called")
        return super(newStyleClass, cls).__new__(cls)

    def __init__(self):
        print("__init__ is called")
        print("self is: ", self)

newStyleClass()

结果如下:

__new__ is called
__init__ is called
self is: <__main__.newStyleClass at 0x109290890>
<__main__.newStyleClass at 0x109290890>

创建类实例并初始化的过程中__new____init__被调用的顺序也能从上面代码的输出结果中看出:__new__函数首先被调用,构造了一个newStyleClass的实例,接着__init__函数在__new__函数返回一个实例的时候被调用,并且这个实例作为self参数被传入了__init__函数。

这里需要注意的是,如果__new__函数返回一个已经存在的实例(不论是哪个类的),__init__不会被调用。如下面代码所示:

obj = 12 
# obj can be an object from any class, even object.__new__(object)

class returnExistedObj(object):
    def __new__(cls):
        print("__new__ is called")
        return obj

    def __init(self):
        print("__init__ is called")

returnExistedObj()

执行结果如下:

__new__ is called
12

同时另一个需要注意的点是:

如果我们在__new__函数中不返回任何对象,则__init__函数也不会被调用。

如下面代码所示:

class notReturnObj(object):
    def __new__(cls):
        print("__new__ is called")

    def __init__(self):
        print("__init__ is called")

print(notReturnObj())

执行结果如下:

__new__ is called
None

可见如果__new__函数不返回对象的话,不会有任何对象被创建,__init__函数也不会被调用来初始化对象。

总结几个点

  1. __init__不能有返回值

  2. __new__函数直接上可以返回别的类的实例。如上面例子中的returnExistedObj类的__new__函数返回了一个int值。

  3. 只有在__new__返回一个新创建属于该类的实例时当前类的__init__才会被调用。如下面例子所示:

class sample(object):
    def __str__(self):
        print("sample")

class example(object):
    def __new__(cls):
        print("__new__ is called")
        return sample()

    def __init__(self):
        print("__init__ is called")

example()

输出结果为:

__new__ is called
sample

如果对于参考答案有不认同的,大家可以在评论区指出和补充,欢迎留言!

10、说说Python可变与不可变数据类型?

11、说说Python模块主要分哪三类?

12、列举Python中的标准异常类?

13、Python中深拷贝与浅拷贝的区别?

14、Python中迭代器和生成器的区别?

15、Python可迭代对象怎么获取迭代器?

16、你了解什么是 Python 之禅么?

17、说说Python字典以及基本操作?

18、说说Python有几种字符串格式化?

19、说说Python多线程与多进程的区别?

20、说说HTTP常见响应状态码?

21、Python 单引号、双引号、三引号区别?

22、说说Python中猴子补丁是什么?

23、说说Python中的垃圾回收机制?

24、Python中有几种交换两个变量的值?

25、说说Python中的6种位运算符?

26、说说Python中的类型转换有哪些?

27、Python中实现二分查找的2种方法?

28、说说Python中的lambda表达式?

29、说说Python中的反射是什么?

30、Python删除list的重复元素有几种方法?

关注小猿公众号,每天学习一道题

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小猿666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值