__new__ 和 __init__ 有什么区别?在什么场景下需要重写 __new__?
有些同学在用 Python 的时候,经常会搞不清楚 __new__ 和 __init__ 这俩魔法方法到底谁先谁后,甚至一度觉得只要写 __init__ 就够了,__new__ 根本用不上。其实它们职责完全不同,而且有些特殊场景,__new__ 是必须要重写的。
new 和 init 的区别
你可以这么理解:
__new__是造房子的工厂,它决定要不要建一个新房子,建什么样的房子,甚至能返回一个完全不同类型的房子。__init__是装修队,等房子建好之后,它才进去刷漆、装家具,把对象的属性都配置好。
从执行顺序上,__new__ 先被调用,它必须返回一个实例(通常是当前类或者子类的实例),然后才会进入 __init__ 进行初始化。如果 __new__ 不返回当前类的实例,那 __init__ 根本不会被调用。
来个简单的例子直观感受下:
classDemo:
def__new__(cls, *args, **kwargs):
print("__new__ called")
instance = super().__new__(cls)
return instance
def__init__(self, name):
print("__init__ called")
self.name = name
d = Demo("Python")
运行结果:
__new__ called
__init__ called
可以看到,先走 __new__ 再走 __init__。
什么时候需要重写 new?
一般情况下,写 __init__ 就够了,__new__ 的场景比较少,但不是没有,典型的有以下几类:
实现单例模式有时候我们只想要一个对象,这时候 __new__就能控制返回的实例。
classSingleton:
_instance = None
def__new__(cls, *args, **kwargs):
if cls._instance isNone:
cls._instance = super().__new__(cls)
return cls._instance
def__init__(self, value):
self.value = value
a = Singleton(10)
b = Singleton(20)
print(a.value, b.value) # 都是20,说明指向同一个实例
print(a is b) # True
继承不可变类型时(如 str、tuple、int)不可变对象(immutable)它们的内容不能通过 __init__来改动,只能在__new__里处理。
classMyStr(str):
def__new__(cls, content):
# 在这里把字符串改成大写
return super().__new__(cls, content.upper())
s = MyStr("hello")
print(s) # 输出 HELLO
想要控制实例化逻辑比如说根据条件返回不同的类实例。
classAnimal:
def__new__(cls, kind):
if kind == "dog":
return Dog()
elif kind == "cat":
return Cat()
return super().__new__(cls)
classDog:
defspeak(self):
return"woof"
classCat:
defspeak(self):
return"meow"
a = Animal("dog")
print(a.speak()) # woof
这种情况下,Animal 根本不会生成实例,而是交给别的类。
所以总结下:
__new__决定“建不建房子、建什么房子”,是创建阶段。__init__负责“装修房子”,是初始化阶段。重写 __new__的常见场景:单例模式、继承不可变类型、返回不同类实例。
你要是只是写一般业务类,那 __init__ 足够用了,除非碰到上面这些“特殊需求”,才需要动 __new__。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领