Python技术迷

什么是 Python 的 __init__ 方法?

有个 Python 初学者,问我:“哥,__init__ 是干啥用的?是不是构造函数?”我一听,差点没被这问题噎住。这玩意儿你说简单吧,一句话“对象初始化”,说完了。但你真要理解透,恐怕得踩上几脚坑,才能恍然大悟:“原来是这么回事儿!”

我先说个场景,感受一下哈👇:

classDog:
def__init__(self, name):
        self.name = name

d = Dog("旺财")
print(d.name)  # 输出:旺财

初看这段代码,好像也没啥,就是构造一个 Dog 类的对象,把名字存起来呗。但你知道 Python 背后的机制有多精妙吗?

说实话,__init__ 其实不是“构造函数”,它更像是“初始化器”。真正构造对象的是 __new__,但大部分时候我们压根不会碰 __new__,除非你在造 metaclass、做一些极端黑魔法。__init__ 是在对象被构造之后调用的,也就是说,self 这个对象已经诞生了,__init__ 就是给它“赋魂”的那一步。

有朋友可能会问,那我不写 __init__ 会咋样?其实也没啥,Python 不会报错,默认啥都不干,比如这个例子:

classCat:
pass

c = Cat()
print(c)  # <__main__.Cat object at 0x...>

对象还是能实例化,只是你没给它任何初始化逻辑。就好像你造了辆车,但没加油也没设定颜色,造是造出来了,但不能开。

咱们再举个稍微复杂点的例子:

classUser:
def__init__(self, username, age):
        self.username = username
        self.age = age

defsay_hi(self):
        print(f"大家好,我是 {self.username},今年 {self.age} 岁了~")

u = User("张三", 28)
u.say_hi()

你看,__init__ 就是把这对象的一些关键数据“注入”进去,不然你怎么可能用 u.say_hi() 的时候知道他是谁多大呢?

那问题来了:为啥叫 __init__,不叫 initialize?很简单,Python 走的是“魔术方法”那一套,__xx__ 命名就是表示这个方法是 Python 内部保留的特殊用法,像 __str__、__repr__、__len__、__getitem__,都是一伙的。你别看这些方法名字丑,但都挺有来头。__init__ 就是专门负责初始化对象的那位。

讲真,刚学 Python 的时候,我也被这个搞懵过。尤其是看到某些奇葩代码:

classConfuse:
def__init__(self):
return"不能返回值!!!"

c = Confuse()  # 报错

没错,你在 __init__ 里返回东西是会直接报错的。因为它的返回值必须是 None,否则 Python 会直接 throw 异常:“TypeError: init() should return None, not 'str'”。

这时候有些人脑子一热,就开始整活:

classHack:
def__new__(cls):
        instance = super().__new__(cls)
        print("先构造对象")
return instance

def__init__(self):
        print("再初始化对象")

h = Hack()

这才是完整流程:__new__ 负责“造对象”,__init__ 负责“初始化对象”。

有意思的是,在数据类 (dataclass) 出来之前,我们很多时候写类都要老老实实地写个 __init__,很繁琐。你得自己接参数、绑属性,一不小心参数顺序还错了。但 Python 3.7 之后的 @dataclass 真的是福音:

from dataclasses import dataclass

@dataclass
classProduct:
    name: str
    price: float

p = Product("iPhone", 8999.99)
print(p.name, p.price)

自动生成 __init__,你说香不香?✨

不过别以为 dataclass 万能,复杂场景你还是得回归手写 __init__,不然遇到自定义逻辑你就卡壳了。

哦对了,说个小段子,有一次一个哥们儿在公司项目里写了个类,结果实例化后属性都是 None,结果 debug 半天发现他把 __init__ 写成了 __inti__,你说这玩意儿能不坑爹吗?😂

最后一个注意事项,有时候我们会看到继承的时候也要写 __init__,这时候记得一定要手动调用父类的 __init__:

classParent:
def__init__(self, name):
        self.name = name

classChild(Parent):
def__init__(self, name, age):
        super().__init__(name)
        self.age = age

不然你继承来的属性压根没初始化成功,后面用就报错,典型的“祖传 Bug”。

所以总结一下,__init__ 是 Python 面向对象里一个至关重要的魔术方法,它不像 Java 那种构造函数直接 new 的时候干所有事儿,它是一个“后处理器”,你先构造好对象,然后由它来决定这个对象初始状态长啥样。

写类不写 __init__ 是可以的,但想写得漂亮用得舒服,那就得把这个方法玩明白了。

兄弟们你们写类的时候,有没有什么关于 __init__ 的奇葩经历?欢迎留言一起吐槽,Python 这语言就是这样,简单的东西里藏着很多门道🐍

最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek

对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
🔥虎哥私藏精品 热门推荐🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,全部免费领取