__new__和__init__的区别
不得不说,Python这门语言,真是写着写着就容易掉坑。最近在复习一些面试题的时候,又翻到了那个让不少人一脸懵逼的魔法方法:__new__ 和 __init__。
你说__init__吧,大家都挺熟,毕竟天天写类的时候离不开它;但这__new__,啧,真是冷门得像是仓库里落灰的老配置,平时也不咋用,但偏偏在面试里总爱冒出来吓唬人。
行吧,今天咱就把这俩货捋一捋,顺便来点代码实践,看看它们到底有啥不同,别到时候面试官一问你就“emmm……”,那多尴尬。
先说__init__,这是个老朋友
简单点说,__init__就是初始化实例用的。比如:
classDog:
def__init__(self, name):
print("Calling __init__")
self.name = name
dog = Dog("Buddy")
这玩意儿谁没写过?实例化对象的时候,__init__就会自动调用,负责给这个对象设定一些初始状态,比如这儿给狗取了个名字。
但注意,__init__其实不负责创建实例,它只是给已经创建好的实例“打扮打扮”,设置点属性啥的。
再看__new__,这是真·冷门
__new__才是负责“制造”实例的那个家伙。它是在对象创建之前被调用,负责返回这个实例。说白了,你要是想控制实例的生成过程,就得用__new__出马。
来看个栗子:
classDog:
def__new__(cls, name):
print("Calling __new__")
instance = super().__new__(cls)
return instance
def__init__(self, name):
print("Calling __init__")
self.name = name
dog = Dog("Buddy")
运行结果:
Calling __new__
Calling __init__
是不是发现了?__new__先调用,负责返回一个实例,然后__init__才上去给它“装扮”。
这俩到底有啥区别?
__new__是个静态方法,专门负责创建实例,返回的就是这个实例对象。__init__是个实例方法,专门负责初始化实例,啥也不返回,只是操作一下传进来的实例。如果 __new__不返回一个实例,那__init__就不会被调用,毕竟没有对象可初始化,咋初始化?
而且,__new__一般只有在需要自定义元类(metaclass)或者做单例模式时才用得着。平时写类,基本靠__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, name):
self.name = name
a = Singleton("A")
b = Singleton("B")
print(a is b) # True
print(a.name) # B
看到没?无论实例化多少次,a和b其实是同一个对象,这就是__new__的威力,专治实例重复。
那元类(metaclass)是啥?
元类是用来创建类的“类”。类是对象,对象有类,类自己也有类——这就是元类,通常是type。
如果你想在类创建时动点手脚,比如自动加点方法、属性啥的,就得靠元类。元类跟__new__、__init__分别负责类创建、实例创建、实例初始化三个阶段,分工明确,各司其职。
不过面试真问你元类,咱劝你一句:别慌,直接说“我平时用得不多,但知道它是用来控制类生成过程的”,别瞎扯,越扯越乱。
面试官问你:__new__ 和 __init__ 有啥区别?
最优回答:
`__new__`是一个静态方法,负责创建实例对象,它会返回这个实例;`__init__`是一个实例方法,用来初始化这个实例对象,不返回值。创建实例时,`__new__`先执行,返回实例后才会调用`__init__`。如果`__new__`返回的不是这个类的实例,`__init__`就不会被调用。一般情况下我们用`__init__`就够了,只有在需要控制实例生成过程时才会用到`__new__`,比如实现单例模式或者自定义元类。
这回答,既不啰嗦,又有重点,面试官听了估计得点头。要是再加一句:“平时基本用不到__new__,但知道它在对象创建过程中起作用”,就更稳了。
说实话,我觉得Python这些魔法方法设计得挺有意思,但有时候也是真绕。__init__天天用,__new__冷不丁冒出来,总得踩几次坑才记住。程序员这行,别怕坑,掉多了反而记得牢。
也可以看我写的这篇文章《DeepSeek满血复活,直接起飞!》来进行本地搭建。
对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。