__new__和__init__的区别。
先说结论:__new__ 是真正创建对象的,是类的构造器,而 __init__ 是初始化器,用来初始化这个刚造好的对象。
是不是有点拗口?我整点实打实的例子和段子给你解释明白 👇
说一个很经典的类比:
__new__就像你点了个外卖,商家开始做饭了,这是创建过程。__init__是骑手把饭送到你手上,你打开包装加点辣条和酱油,这是初始化过程。
代码怎么写?👇
classDemo:
def__new__(cls, *args, **kwargs):
print("执行 __new__ 方法")
instance = super().__new__(cls)
return instance
def__init__(self, name):
print("执行 __init__ 方法")
self.name = name
obj = Demo("Python哥")
输出是这样的:
执行 __new__ 方法
执行 __init__ 方法
重点来了:__new__ 在对象还没生成之前调用,返回一个“空壳”;__init__ 是在壳子已经生成之后填充内容的。
那为啥我们平时几乎不重写 __new__ 呢?
因为 80% 的时候你用不到它。除非你搞的是:
单例模式(必须确保全世界只能有一个对象) 不同输入创建不同类型的对象(你搞点魔法方法逻辑) 你继承了不可变类型,比如 int、str,必须用__new__
比如说搞个单例:
classSingleton:
_instance = None
def__new__(cls, *args, **kwargs):
if cls._instance isNone:
cls._instance = super().__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b) # True,说明是同一个实例
这个场景下,不用 __new__ 你根本没法搞定。
如果你 __new__ 返回的不是当前类的实例,那 __init__ 根本不会被调用。
看看这个反例:
classTest:
def__new__(cls):
print("new")
return"一个字符串"
def__init__(self):
print("init") # 不会执行
t = Test()
print(type(t)) # <class 'str'>
这玩意儿常被拿来出面试题,估计就是为了坑你一下 😅
还有种面试官的骚操作是:让你继承 int 搞个增强版整数类。
classMyInt(int):
def__new__(cls, value):
print(f"new {value}")
return super().__new__(cls, value)
def__init__(self, value):
print(f"init {value}")
a = MyInt(5)
print(a + 3) # 8
这你就得知道,int 是不可变类型,想扩展只能靠 __new__,不然根本没机会修改对象本身。
说个真实项目踩过的坑。有一次我们搞一个 ORM 系统,模型类继承了 str,用来包一层带验证的字段。结果一个兄弟写了个验证逻辑放 __init__,然后死活不生效。为啥?因为 str 是不可变类型,它压根不调用 __init__。最后只能把逻辑塞到 __new__ 里才搞定。
总结一下:
__new__是用来“造对象”的,常见于不可变类型、自定义元类、单例;__init__是用来“初始化对象”的,基本你每个类都会写;如果 __new__返回的不是实例,__init__不会执行;多数时候你用不到 __new__,除非你真想“搞点事”。
说实话,这玩意儿如果不是自己用到过,靠看文档记不住。最好的方式就是写几个奇怪的类,调试一遍你就彻底懂了。
最后送你一句话面试保命口诀:
new 是开模具,init 是组装件,搞清顺序别翻车,面试拿下不白练。
你要是再想挑战自己,研究下 metaclass 和 __call__,那才是 Python 黑魔法的最终形态,专治各种“我就想整点花的”。
-END-
我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领