python -m
python -m
在命令行中使用python时,cpython解析器会扫描命令行参数以及环境进行相应的操作和设置.输入文件名调用时,直接执行该脚本:
1 | python myscript.py |
使用-m module-name
调用时,在sys.path 中搜索指定模块,并以__main__ 模块执行其内容。
1 | python -m myscript |
说明1
sys.path
python之所以能够导入一个模块(import module
),是因为这个模块所在的目录在sys.path里,否则是无法进行导入的。在不同的虚拟环境中启动python时,他们的sys.path变量不同,因此在导入包时导入的就是相应环境中的包.
sys.path
在lab环境下的输出:
1 | ['C:\\Users\\shen\\Lab', |
sys.path
在base环境下的输出:
1 | ['C:\\Users\\shen\\Lab', |
因此想导入自己的模块时,最简单的方法就是把对应的python文件直接放到当前的工作目录下,工作目录就在sys.path中。sys也提供了一些其他接口,此外也可以使用PYTHONPATH环境变量来添加新目录:
PYTHONPATH环境变量始终放在sys.path的最上层
python 运行和 python -m 运行时sys.path的区别
新建G:.py文件如下:
1 | import sys |
分别用 python
和 python -m
运行:
直接启动时,解释器把py文件所在的目录添加到了sys.path中,而模块启动时,把输入命令所在的目录添加到了sys.path中
直接运行脚本必须给出脚本的完整路径,而模块启动时,解释器会自动在sys.path里寻找这个模块所在的位置,因此可以直接在命令行里调用python的某些模块,使用一些模块提供的功能(如果它提供了命令行接口),比如timeit模块:
说明2
模块就是一个.py文件,而包是堆模块更高级的封装,python要求每一个包的目录下必须有一个__init__.py
文件,python -m
的参数应该是一个模块文件,如果后面的参数是一个包名称时,此时需要包的路径下有一个__main__.py
文件,解释器把__main__.py
文件作为主模块执行。新建G:,在该目录下新建空的__init__.py
和__main__.py
文件,编辑__main__.py
文件如下:
1 | import sys |
python -m package
运行结果如下:
说明3 - 包的导入
在导入一个包时,实际上是运行它的
__init.py__
文件,因此要想通过导入的包调用子模块时,需要在__init__.py
文件中导入;导入一个模块时,实际上就是运行相应的.py文件。理解了这一点就理解了很多逻辑.包
__init__.py
文件中的__all__
变量:当不指明
__all__
变量时,运行from package import *
时会导入package中的所有定义的符号,当指明__all__
变量时,只有存在于__all__
中的符号才会被导入:目录结构如下:
package
├─
__init__.py
├─subpackage_B
├─module_B.py└__init__.py
├─subpackage_A
├─module_A.py└__init__.py
其中package下的
__init__.py
文件为:1
from . import subpackage_A,subpackage_B
subpackage_A下的
__init__.py
文件为:1
from . import module_A
subpackage_B下的
__init__.py
文件为:1
from . import module_B
module_A.py文件中定义了一个A变量,module_B.py文件中定义了一个B变量.
若在package的
__init__.py
文件中不声明__all__
变量,则subpackage_A和subpackage_B都会被导入:
若定义__all__
变量如下:
1 | __all__ = ['subpackage_A'] |
则只有subpackage_A会被导入
__name__
变量__name__
变量是一个模块的属性,当直接执行一个脚本的时候,这个脚本的__name__
变量为__main__
,当作为模块导入时,这个模块的__name__
变量为它本身的名字.__package__
变量__package__
变量在PEP 366中引入,它是一种允许显式相对导入的机制。__package__
变量是一个模块具有的属性。__package__
变量有三种可能的值,对应三种可能的情况:(1) 一个包的名字:这个模块本身就是一个包(在python里包的类型也是module),如下面的package和package.subpackage_A,这时他们的
__package__
就是他们的__name__
。当它不是一个包而是一个模块时(也就是一个.py文件时),他们的__package__
名字是他们所在的包.1
2
3
4
5
6
7
8
9import package
def func(module_or_package):
print('__name__:', module_or_package.__name__)
print('__package__:',module_or_package.__package__,'\n')
func(package)
func(package.subpackage_A)
func(package.subpackage_A.module_A)输出为:
1
2
3
4
5
6
7
8__name__: package
__package__: package
__name__: package.subpackage_A
__package__: package.subpackage_A
__name__: package.subpackage_A.module_A
__package__: package.subpackage_A(2) 一个空的字符串:一个单独的模块,不在某一个包里面,这个空字符串就代表顶级模块
(3)
None
:如果用文件名直接运行这个模块(.py文件),它的__package__
值为None
考虑下面一个情形,目录结构如下:
目录结构如下:
package1
├─
__init__.py
├─module.py
package2
├─
__init__.py
├─run.py
package1和package2在同一目录下,编辑run.py如下:
1 | print('__name__:',__name__) |
运行:
1 | python package2/run.py |
输出为:
1 | __name__: __main__ |
因为此时run.py是一个文件,package1对于他来说是不可见的;
运行:
1 | python -m package2.run |
输出为:
1 | __name__: __main__ |
此时package2所在的目录在sys.path里,所以package1也是可见的,不会报错.
参考:
https://docs.python.org/zh-cn/3/using/cmdline.html
https://www.jianshu.com/p/04701cb81e38
https://python3-cookbook.readthedocs.io/zh_CN/latest/c10/p09_add_directories_to_sys_path.html
https://www.cnblogs.com/xueweihan/p/5118222.html
https://stackoverflow.com/questions/22241420/execution-of-python-code-with-m-option-or-not
https://www.jb51.net/article/174005.htm
https://stackoverflow.com/questions/21233229/whats-the-purpose-of-the-package-attribute-in-python
https://blog.csdn.net/weixin_38256474/article/details/81228492