Python 模块与包详解:from 导入、包结构、init.py、绝对 / 相对导入
摘要
本文详解 Python 模块导入from xxx import xxx、from xxx import *规则,系统讲解Python 包概念、__init__.py作用、项目目录搭建、包两种导入方式(绝对导入、相对导入),罗列导包常见踩坑点,附带完整可运行源码,适合零基础学习 Python 包管理。
关键字:Python 包、init.py、相对导入、绝对导入、模块导入、all
一、from xxx import * 与 all 导入规则
1.1 核心规则
-
from 模块 import *:一次性导入模块所有可用变量、函数 -
模块内定义
__all__ = ["变量名","函数名"]:*只会导入列表内声明内容,不在列表中的内容无法通过*导入 -
无
__all__:默认导出模块全部全局成员
1.2 示例代码
[haha.py](haha.py)
# haha.py
__all__ = ["money", "chi"]
money = 100
def chi():
print("我是吃")
def he():
print("我是呵呵")
[test.py](test.py)
# test.py
from haha import *
chi()
print(money)
# he() # 报错,he不在__all__列表中
二、Python 包基础概念
2.1 什么是包
包是使用.划分命名空间的文件夹,Python2 必须带**__init__.py文件,Python3 可省略,但规范开发建议所有包目录都创建__init__.py**;
包本质是特殊模块,创建目的:分类管理大量模块文件,优化项目目录结构、提升代码可维护性。
2.2 自动创建案例目录结构代码
执行下面代码一键生成示例项目glance包目录:
import os
# 创建多级目录
os.makedirs('glance/api')
os.makedirs('glance/cmd')
os.makedirs('glance/db')
# 批量创建__init__.py与业务py文件
file_list = [
open('glance/__init__.py','w'),
open('glance/api/__init__.py','w'),
open('glance/api/policy.py','w'),
open('glance/api/versions.py','w'),
open('glance/cmd/__init__.py','w'),
open('glance/cmd/manage.py','w'),
open('glance/db/__init__.py','w'),
open('glance/db/models.py','w')
]
# 关闭所有文件句柄
list(map(lambda f: f.close(), file_list))
2.3 最终项目目录结构
| 目录 / 文件 | 说明 |
|---|---|
| glance/ | 顶级包 |
| ├─init.py | 包初始化文件 |
| ├─api/ | 子包 api |
| │ ├─init.py | 子包初始化 |
| │ ├─[policy.py](policy.py) | 业务模块 |
| │ └─[versions.py](versions.py) | 业务模块 |
| ├─cmd/ | 子包 cmd |
| │ ├─init.py | 子包初始化 |
| │ └─[manage.py](manage.py) | 业务模块 |
| └─db/ | 子包 db |
| ├─init.py | 子包初始化 |
| └─[models.py](models.py) | 业务模块 |
2.4 填充各模块测试代码
[policy.py](policy.py)
# glance/api/policy.py
def get():
print('from policy.py')
[versions.py](versions.py)
# glance/api/versions.py
def create_resource(conf):
print('from version.py: ', conf)
[manage.py](manage.py)
# glance/cmd/manage.py
def main():
print('from manage.py')
[models.py](models.py)
# glance/db/models.py
def register_models(engine):
print('from models.py: ', engine)
三、包的两种导入语法:import /from ... import
3.1 import 完整路径导入
# test.py
# 完整层级导入模块
import glance.db.models
glance.db.models.register_models('mysql')
3.2 from xxx import xxx 导入
语法限制:
from a.b import c合法;from a import b.c非法,import 后不能带.
# test.py from glance.api.policy import get get()
四、init.py 核心作用
4.1 执行时机
首次导入包 / 包子模块时,自动执行当前包下的**__init__.py**,可编写初始化代码、预导入内容、配置__all__控制from 包 import *导出内容。
4.2 _\all\_控制 * 导入示例
glance/init.py
# glance/__init__.py
print("我是glance的__init__.py文件. ")
x = 10
def hehe():
print("我是呵呵")
def haha():
print("我是哈哈")
# 限定*导入的内容
__all__ = ['x', "hehe"]
[test.py](test.py)
# test.py
from glance import *
print(x)
hehe()
# haha() # 报错,haha不在__all__内
五、包内:绝对导入 & 相对导入
使用场景:包内部各个子模块之间互相导入
| 导入类型 | 规则 | 符号 |
|---|---|---|
| 绝对导入 | 以项目顶级包名开头完整路径导入 | 无特殊符号 |
| 相对导入 | .当前目录,..上级目录,只能在包内部使用 | . / .. |
5.1 绝对导入(推荐,无运行限制)
在glance/api/versions.py中导入 cmd 模块:
# glance/api/versions.py
# 绝对导入:从顶层glance开始写全路径
from glance.cmd import manage
manage.main()
5.2 相对导入
# glance/api/versions.py
# .. 代表上级目录glance,跨子包导入
from ..cmd import manage
manage.main()
⚠️ 重要坑:带有相对导入的 py 文件不能直接作为入口脚本运行,否则报错
attempted relative import beyond top-level package,只能在外部通过导入包使用。
六、导包高频踩坑点
坑 1:同目录直接 import 模块,外部导包报错
[policy.py](policy.py) 直接写import versions,本地单独运行 policy 正常;外部import glance.api.policy时报错ModuleNotFoundError
# glance/api/policy.py
# 错误写法
import versions
# 正确写法(绝对导入)
from glance.api import versions
原因:单独运行脚本和外部导入时sys.path搜索路径不一致,跨项目导入找不到模块,导包异常优先打印print(sys.path)排查路径。
坑 2:直接 import 顶级包无法调用子模块
# test.py
import glance
# glance.db.models.register_models("mysql") # 报错,默认不会自动加载子包
解决方案:在glance/__init__.py提前导入子包
# glance/__init__.py # 绝对导入预加载子包 from . import api from . import cmd from . import db
七、包导入通用硬性规范
-
导入语句中带**
.时,.左侧必须是包**,如a.b.c,b 必须是 a 的子包、c 是 b 内模块; -
import 包名,命名空间内容来自包下__init__.py; -
不同包下同名模块不会冲突,
A.a和B.a分属两个独立命名空间。
结语
本文完整覆盖 Python 包入门全知识点,代码可直接复制运行,掌握__init__.py、绝对 / 相对导入后即可规范搭建大中型 Python 项目目录。
更多推荐




所有评论(0)