深入理解 Python 的 __name__ == "__main__" 与双下划线(dunder)机制
很多 Python 初学者都会在代码里看到这样一行,却长期"照抄不理解":
python
if __name__ == "__main__":
main()
这一行并不是"语法糖",而是 Python 模块系统和工程设计的核心机制之一。
一、什么是双下划线(Dunder)?
在 Python 中,形如:
python
__name__
__init__
__call__
这种 前后各两个下划线 的名字,被称为:Dunder(Double Underscore)
它们不是普通变量或方法,而是:
由 Python 解释器定义和调用的"语言级接口,相当于 Python 的"系统保留 API"。
二、__name__ 是什么?
1. __name__ 是一个内置变量
每一个 Python 文件(模块)在加载时,都会被赋予一个 __name__
python
print(__name__)
2. 两种运行方式,两种值
情况一:文件被直接运行
bash
python app.py
python
__name__ == "__main__"
情况二:文件被 import
python
import app
python
app.__name__ == "app"
三、if __name__ == "__main__" 到底在干什么?
1. 本质含义(一句话)
"只有当我作为程序入口运行时,才执行下面的代码"
2. 示例
python
def main():
print("程序启动")
if __name__ == "__main__":
main()
直接运行
bash
python demo.py
输出:
text
程序启动
被 import
python
import demo
无输出。
3. 为什么这是 Python 的"工程标准"?
因为它让 一个文件同时具备两种角色:
| 角色 | 行为 |
|---|---|
| 脚本(script) | 可直接运行 |
| 模块(module) | 可被复用 |
四、如果没有这个判断会发生什么?
错误示例
python
print("连接数据库")
python
import db_utils
👉 import 就执行副作用代码
这是 Python 项目里最常见的坑之一。
五、常见双下划线变量(Dunder Variables)
1️⃣ __name__
python
print(__name__)
- 当前模块名
- 入口判断的核心
2️⃣ __file__
python
print(__file__)
- 当前文件的绝对路径
- 常用于加载配置、资源文件
python
BASE_DIR = os.path.dirname(__file__)
3️⃣ __dict__
python
class User:
def __init__(self, name):
self.name = name
u = User("Tom")
print(u.__dict__)
输出:
python
{'name': 'Tom'}
👉 对象的属性存储容器
六、常见双下划线方法(Magic Methods)
1️⃣ __init__ ------ 构造函数
python
class User:
def __init__(self, name):
self.name = name
- 对象创建时自动调用
- 用于初始化状态
2️⃣ __str__ ------ 打印友好表示
python
class User:
def __str__(self):
return "User object"
print(User())
输出:
text
User object
3️⃣ __repr__ ------ 开发者表示
python
class User:
def __repr__(self):
return "User(name=Tom)"
4️⃣ __call__ ------ 让对象"像函数一样"
python
class Adder:
def __call__(self, a, b):
return a + b
add = Adder()
print(add(1, 2))
输出:
text
3
👉 函数式编程 + 面向对象的结合点
5️⃣ __len__ ------ 支持 len()
python
class MyList:
def __len__(self):
return 10
print(len(MyList()))
6️⃣ __getitem__ ------ 支持下标访问
python
class Box:
def __getitem__(self, index):
return index * 2
b = Box()
print(b[3])
输出:
text
6
七、__main__ 是什么?
"__main__" 不是变量,是一个约定的模块名:
- Python 启动时
- 会把"入口文件"的模块名设置为
"__main__"
这也是为什么入口判断写成:
python
if __name__ == "__main__":
八、工程实践中的标准写法
推荐结构
python
def main():
...
if __name__ == "__main__":
main()
好处:
- 入口清晰
- 可测试
- 可 import
- 可复用