Python中init.py文件的作用
技术背景
在Python中,__init__.py 文件曾经是Python包(在Python 3.3之前的“常规包”)的必要组成部分。Python定义了两种类型的包:常规包和命名空间包。常规包通常是一个包含 __init__.py 文件的目录,当导入该包时,__init__.py 文件会被隐式执行,其定义的对象会绑定到包的命名空间中。而从Python 3.3开始,引入了隐式命名空间包(PEP 420),不再要求使用 __init__.py 文件来定义可导入的Python包。
实现步骤
标记目录为Python包
如果目录结构如下:
mydir/
spam/
__init__.py
module.py
当 mydir 在Python的搜索路径中时,可以使用以下方式导入 module.py 中的代码:
import spam.module
或者
from spam import module
若移除 __init__.py 文件,Python将不再将该目录视为包,尝试导入模块将会失败。
包级变量定义与便捷导入
在包中频繁使用的对象可以在 __init__.py 中定义,方便其他模块导入。例如,有如下包结构:
database/
__init__.py
schema.py
insertions.py
queries.py
在 __init__.py 中定义数据库会话:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
在其他模块中可以直接导入 Session:
from database import Session
session = Session()
使用 __all__控制导入
__init__.py 中的 __all__ 变量可以控制使用 from package import * 时导入的子模块。例如,在 subPackage_b 的 __init__.py 中:
__all__ = ['module_n2', 'module_n3']
当执行 from package_x.subPackage_b import * 时,只有 module_n2 和 module_n3 会被导入。
核心代码
定义包级变量
# database/__init__.py
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
使用 __all__控制导入
# subPackage_b/__init__.py
__all__ = ['module_n2', 'module_n3']
包初始化代码
# pymodlib/__init__.py
print(f'Invoking __init__.py for {__name__}')
pystructures = ['for_loop', 'while__loop', 'ifCondition']
最佳实践
- 保持 __init__.py 简洁:遵循“显式优于隐式”的原则,避免在 __init__.py 中写入过多复杂代码。
- 使用 __all__ 控制导入:当需要控制 from package import * 的行为时,使用 __all__ 变量明确指定要导入的子模块。
- 定义常用对象:将频繁使用的对象定义在 __init__.py 中,方便其他模块导入。
常见问题
Python 3.3之后是否还需要 __init__.py
从Python 3.3开始,__init__.py 不再是定义可导入Python包的必需文件,但为了明确指示该目录是一个包,建议仍然包含它,即使它是空的。
如何在Python 2中加载同级文件
在Python 2中,如果要加载同级文件,可以将当前文件的父目录添加到系统路径中:
import os
import sys
dir_path = os.path.dirname(__file__)
sys.path.insert(0, dir_path)
import cheese
from vehicle_parts import *
不过,建议尽量使用 __init__.py 文件来管理包。