1. 适用范围:
从一个模块导入并执行另一些包、模块、类、函数、实例对象
2. 相关概念:
2.1. 包:
严格意义上,含有__init__.py文件的目录才是包,通常多个模块组成一个包
导入一个包之后,会隐式执行__init__.py
但就导入而言, 只要是目录都可以算是包
2.2. 模块:
即一个abc.py文件就是模块
2.3. 顶层包:
即在导入中最高级的可见包
2.4. 包的层级结构(python形式的路径):
即用.代替传统文件路径的/
2.5. 包的层级结构的可见性:
python导入时能看到顶级包内的所有包和子包,不能看到与顶级包同级的其他包。综上,包的可见性影响因素只有一个,那就是顶层包
2.6. 入口程序:
入口程序指的是被直接执行的模块,即abc.py
2.7. child::python -m 带m参数运行模块
1. 适用范围:
可以用于在用到import语句时指定顶级模块,详见python import详解
2. 用法:
python -m 包名.模块名
其中包名前面还可以加包名,也可以单独就一个模块名
现有一个test.py
则模块名就是test
指向原始笔记的链接
python -m 带m参数运行模块
1. 适用范围:
可以用于在用到import语句时指定顶级模块,详见python import详解
2. 用法:
python -m 包名.模块名 其中包名前面还可以加包名,也可以单独就一个模块名 现有一个test.py 则模块名就是test
指向原始笔记的链接3. 梗概:
python中导入按功能和机制分为两种导入,一种是绝对导入,另一种是相对导入
另外, 导入之后会运行该对象, 如导入了一个模块, 则会运行该模块的代码; 如导入一个函数, 则会运行定义这个函数的代码块.
而用 if __name__ == '__main__': 可以使被导入模块的某段代码不被间接运行
3.1. 两种导入通用的机制抽象:
两种导入语法中用的都是包的结构层次(其实就是python形式的路径),两种导入首先都会对语句中的包的层次结构在可见的已知包的结构库中进行查找,找到后就导入 所以关键是弄清楚到最高级的可见包,即顶层包 另外有一个相同的点, 是两种导入方式的顶层包都与入口程序相关 运行了入口程序就确定了顶层模块 然后再由顶层模块根据两种导入的机制最终确定顶层包
3.2. 顶层包的确定:
3.2.1. 顶层模块的确定:
- 根据运行入口程序的方式区分:
- 就直接运行入口程序 (没有指明顶层包) 情况下,即
python xxxx/abc.py此时python xxxx/abc.py中的xxx/abc.py表示用的是文件的路径形式 默认顶层模块就是abc.py - 就间接运行入口程序(指明顶层包)情况下,即
python -m xxxx.abc注意此时python -m xxxx.abc中的xxxx.abc表示用的是包的层级结构 该情况下顶级模块就是xxxx
- 就直接运行入口程序 (没有指明顶层包) 情况下,即
3.2.2. 由顶层模块确定顶层包:
3.2.2.1. 绝对导入:
绝对导入的顶级包只与入口程序的路径有关 绝对导入的顶级包为顶层模块的上一级,即xxxx
3.2.2.2. 相对导入:
相对导入的顶级包与入口程序的路径有关, 还与使用相对导入的模块路径有关
- 顶级包与顶层模块同级(最重要的点)
- 该顶级包包含使用相对导入的模块(这点在实际写import语句时并不需要在意、因为本来就是从当前模块开始写的)
4. 使用方法:
4.1. 实例:
有如下文件结构
home/Test/package1/subpackage/testA.py
/test1.py
/package2/folder/testB.py
/test2.py
/test.py
/outtest.py
其中除了Test和folder都省略了其包含的文件__init__.py 而Test和folder都没有__init__.py文件
4.1.1. 用python -m 参数来间接运行入口程序,并且指定顶层模块
4.1.1.1. 用命令 python -m Test.test 间接运行 test.py, 并且绝对导入 testA 的方法:
- 编写导入语句 解释: 此时有了顶层模块Test,又因为使用的是绝对导入,所以顶级包是顶层模块的上一级,即home
#test.py
#第一种写法:
from Test.package1.subpackage import testA #此时路径初始在顶层包内,直接写顶层包的下一级
#第二种写法:
import Test.package1.subpackage.testA #此时路径初始在顶层包内,直接写顶层包的下一级- 切换到home目录下 解释: 让python在home目录下能根据python形式的文件路径(指Test.test)找到模块test
- 然后在终端输入命令:
python -m Test.test
4.1.1.2. 用命令 python -m Test.package2.folder.testB 间接运行 testB.py, 并且相对导入 testA 的方法:
- 编写导入语句 解释: **此时有了顶层模块Test,又因为使用的是相对导入,所以==顶级包与顶层模块同级,且含有testB模块,即Test
#test.py
from ...package1.subpackage import testA #相对导入路径都是从该模块开始,每一个点表示进入上一级,这里三个点就是进到上三级,即Test包,后面部分就跟绝对导入一致了
- 切换到home目录下 解释: 让python在home目录下能根据python形式的文件路径(指Test.test.package2.folder.testB)找到模块testB
- 然后在终端输入命令:
python -m Test.package2.folder.testB
4.1.2. 直接运行入口程序
4.1.2.1. 用命令python test.py直接运行入口程序test.py,并且绝对导入test1
- 按照语法写绝对导入语句 解释: 此时顶级模块为test,又因为是绝对导入,所以顶层包为test的上一级,即Test
#test.py
#第一种写法
from package1 import test1 #此时路径初始在顶层包内,直接写顶层包的下一级
#第二种写法
import package1.test1 #此时路径初始在顶层包内,直接写顶层包的下一级- 切换到Test目录下 解释: 让python在Test目录下能根据文件路径形式(指test.py)找到模块test.py
- 然后在终端输入命令:
python test.py
5. 相关报错解决方案
查看该板块前应先查看5. 大致原理板块
5.1. 直接运行含相对导入语句的文件报错:
直接运行该模块,则该模块的__name__属性为__main__,这时python根据__name__属性分析不出包的层级结构,就会报错
5.2. 使用相对导入时报错ValueError: Attempted relative import beyond toplevel package
由报错信息得超过了顶层包
可以通过 print(__name__) 打印出 __name__ 属性, 相对导入得情况下, __name__ 属性最前面的那个就是顶层包