Python常见面试题007. 谈谈Python中__init__和__new__的区别

python,常见,面试题,谈谈,init,new,区别 · 浏览次数 : 85

小编点评

**__init__和__new__方法区别:** | 特征 | __init__ | __new__ | |---|---|---| | 方法类型 | 实例方法 | 静态方法 | | 返回值 | 新实例 | 新实例 | | 方法调用顺序 | 在构造对象期间 | 在实例创建之前调用 | | 使用场景 | 建立不可变类型子类的实例 | 建立可变类型子类的实例 | **__init__方法的功能:** * 初始化实例属性。 * 完成对基类初始化的设置。 * 触发实例的 __init__ 方法。 **__new__方法的功能:** * 创建一个新实例。 * 根据类的类型创建实例。 * 将构造器表达式参数传递给实例构造器。 * 返回新实例。 * 如果 __new__方法返回 None,则实例的 __init__ 方法不会被执行。 **__new__方法的用途:** * 可变类型子类可以通过 __new__ 方法自定义实例创建过程。 * 通过 __new__ 方法实现可变类型子类的构造过程。 * 允许不可变类型子类定制实例创建逻辑。

正文

007. 谈谈Python中__init__和__new__的区别

  • python中关于dunder method双下方法,或magic method魔术方法的描述多在

    https://docs.python.org/zh-cn/3.9/reference/datamodel.html#special-method-names
    

实例演示特性

  1. __new__是个静态方法(要看源码了),__init__是实例方法

  2. __new__需要返回一个实例,如果不返回,新实例的__init__不会被执行

    class Person:
        def __new__(cls, *args, **kwargs):
            return 'new'
    
        def __init__(self):
            print('calling init')
    
    
    wuxianfeng = Person()  # 什么都不会打印,如果注释掉new方法就可以了
    
    
    #当然你也可以这样写
    class Person:
        def __new__(cls, *args, **kwargs):
            instance = super().__new__(cls, *args, **kwargs)
            return instance
    
        def __init__(self):
            print('calling init')
    
    
    wuxianfeng = Person() # 也是会打印的
    
    
  3. __init__只能返回None

    class Person:
        def __init__(self):
            print('calling init')
            return 1
    
    wuxianfeng = Person()
    # 报错 TypeError: __init__() should return None, not 'int'
    # 但是也会输出calling init
    
    
  4. __new__在__init__之前

    class Person:
        def __new__(cls, *args, **kwargs):
            print('calling new')
            instance = super().__new__(cls, *args, **kwargs)
            return instance
    
        def __init__(self):
            print('calling init')
    
    
    wuxianfeng = Person()  # 先打印 calling new 再打印 calling init
    
    
    wuxianfeng = Person()
    
    # 你可以理解为这样的一个过程(参考https://www.bilibili.com/video/BV1b84y1e7hG)
    
    wuxianfeng = __new__(Person)
    
    __init__(wuxianfeng )
    
    
  5. 如果我们在建立一个object的过程中,传入了一些参数,那么这些参数既会被传入到new里也会被传入到init里

    class Person:
        def __new__(cls, x):
            print(f'calling new,and {x}')
            instance = super().__new__(cls)
            return instance
    
        def __init__(self,x):
            self.x = x
            print(f'calling init,and get {self.x}')
    
    
    wuxianfeng = Person('wxf')
    # calling new,and wxf
    # calling init,and get wxf
    
    
    如果在上面的代码中你去掉__new__(cls, x):中的,x,IDE会给你提示:签名不兼容,而且是双向的,new提示不兼容init,init提示不兼容new
    
    
    
    

  • 说在最后
    • __init__是大家都必须要掌握的,也是用的最多的魔术方法了
    • __new__是从一个class建立一个object的过程,如果你要更改这个过程(比如单例中,你在建立object之前要判断是否有建立过obj,从而确定自己是否要再建立),你就可以考虑用__new__
    • __init__是有了上面的__new__出来的object后对它进行初始化的一个过程
    • metaclass里面对new是用的相对多一些

官方说明

  • __new__中文部分

    object.__new__(cls[, ...])
    调用以创建一个 cls 类的新实例。__new__() 是一个静态方法 (因为是特例所以你不需要显式地声明),它会将所请求实例所属的类作为第一个参数。其余的参数会被传递给对象构造器表达式 (对类的调用)。__new__() 的返回值应为新对象实例 (通常是 cls 的实例)。
    
    典型的实现会附带适宜的参数使用 super().__new__(cls[, ...]),通过超类的 __new__() 方法来创建一个类的新实例,然后根据需要修改新创建的实例再将其返回。
    
    如果 __new__() 在构造对象期间被发起调用并且它返回了一个 cls 的实例,则新实例的 __init__() 方法将以 __init__(self[, ...]) 的形式被发起调用,其中 self 为新实例而其余的参数与被传给对象构造器的参数相同。
    
    如果 __new__() 未返回一个 cls 的实例,则新实例的 __init__() 方法就不会被执行。
    
    __new__() 的目的主要是允许不可变类型的子类 (例如 int, str 或 tuple) 定制实例创建过程。它也常会在自定义元类中被重载以便定制类创建过程。
    
  • __new__英文部分

    object.__new__(cls[, ...])
    Called to create a new instance of class cls. __new__() is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of __new__() should be the new object instance (usually an instance of cls).
    
    Typical implementations create a new instance of the class by invoking the superclass’s __new__() method using super().__new__(cls[, ...]) with appropriate arguments and then modifying the newly-created instance as necessary before returning it.
    
    If __new__() is invoked during object construction and it returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to the object constructor.
    
    If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.
    
    __new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.
    
  • __init__中文部分

    在实例 (通过 __new__()) 被创建之后,返回调用者之前调用。其参数与传递给类构造器表达式的参数相同。一个基类如果有 __init__() 方法,则其所派生的类如果也有 __init__() 方法,就必须显式地调用它以确保实例基类部分的正确初始化;例如: super().__init__([args...]).
    
    因为对象是由 __new__() 和 __init__() 协作构造完成的 (由 __new__() 创建,并由 __init__() 定制),所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError。
    
  • __init__英文部分

    object.__init__(self[, ...])
    Called after the instance has been created (by __new__()), but before it is returned to the caller. The arguments are those passed to the class constructor expression. If a base class has an __init__() method, the derived class’s __init__() method, if any, must explicitly call it to ensure proper initialization of the base class part of the instance; for example: super().__init__([args...]).
    
    Because __new__() and __init__() work together in constructing objects (__new__() to create it, and __init__() to customize it), no non-None value may be returned by __init__(); doing so will cause a TypeError to be raised at runtime.
    

与Python常见面试题007. 谈谈Python中__init__和__new__的区别相似的内容:

Python常见面试题007. 谈谈Python中__init__和__new__的区别

007. 谈谈Python中__init__和__new__的区别 python中关于dunder method双下方法,或magic method魔术方法的描述多在 https://docs.python.org/zh-cn/3.9/reference/datamodel.html#special

Python常见面试题001-005,涉及深浅拷贝、MRO、函数可变参数、作用域、is和==的区别等

Python常见面试题001-005 参考资料 https://github.com/taizilongxu/interview_python https://github.com/hantmac/Python-Interview-Customs-Collection https://github.

Python常见面试题006 类方法、类实例方法、静态方法有何区别?

006. Python中类方法、类实例方法、静态方法有何区别? 全部放一个里面篇幅过大了,就拆分成1个个发布 示例代码 class Human: def __init__(self, name): self.name = name def say(self): print(f'我的名字是{self.

Python常见面试题008. 谈谈python中的解包

008. 谈谈python中的解包 这是个简单的知识点,但有的学员并不理解 unpacking解包 解,对应的是*或者**,也有自动解包之说 包对应的可迭代对象 自动解包 赋值的demo a,b = [1,2] print(a) # 1 print(b) # 2 将容器里面的元素逐个取出来分别赋值

Python常见面试题011. 如何在Python中动态创建类?

011. 如何在Python中动态创建类? 说在前面 答案是type 你印象中的type是用来查看对象的类型的 li = [] type(li) # 得到list 对自定义的类是这样的 class Person: pass wuxianfeng = Person() type(wuxianfeng)

Python常见面试题009. 元组和列表有什么区别

009. 元组和列表有什么区别 这个题是简单的,但要拿满分或者说高分不容易 相同点 | 共性 | 说明 | | | | | 可以存放任意元素 | 一般都放同类型 | | 支持索引访问 | 甚至是负数 | | 支持切片操作 | | | 逗号分隔元素 | | | 都是有序集合(容器) | | | 可以随

Python常见面试题010. Python的int占多大内存?

010. Python的int占多大内存? 示例代码 import sys a = 0 print(a.__sizeof__()) # 24 print(sys.getsizeof(a)) # 24 所以答案是24?并不是!看下面 import sys b = 1 print(b.__sizeof_

Python常见面试题012. 可迭代对象和迭代器有啥区别?

012. 可迭代对象和迭代器有啥区别? 2者不是一回事(废话) 比如 from collections.abc import Iterable,Iterator print(isinstance([1, 2], Iterable)) # True 列表是可迭代对象 print(isinstance(

Python常见面试题013.请说出下面的代码返回结果是什么?

013.请说出下面的代码返回结果是什么? *的坑;简单题 参考:https://docs.python.org/zh-cn/3.9/library/stdtypes.html#typesseq 示例代码 lists = [[]] * 3 lists[0].append(1) 请问lists此时是什么

Python常见面试题014.请说出下面的代码返回结果是什么?

示例代码 def fun(a, b, c, d): nums = [] for num in range(a, b): nums.append(lambda: num ** c) return nums[d]() print(fun(1, 5, 2, 0)) print(fun(1, 5, 2, 1