python -m详解
温馨提示: 本篇演示环境是
Python 3.8
先python --help看下python -m参数的解释:
-m mod : run library module as a script (terminates option list)
mod是module的缩写,即-m后面跟的是模块(module)名,意思是把模块当成脚本来运行。
terminates option list意味着-m之后的其它选项不起作用,在这点上它跟-c是类似,都是终极选项。
既然涉及到模块,这里就多提几句。 在Python中,一个.py文件就称之为一个模块(Module)。
比如一个顶层包名bytesfly,按照如下目录存放:
bytesfly
├─ __init__.py
├─ __main__.py
└─ fly.py
上面fly.py模块的名字就是bytesfly.fly。
注意: 模块名是不带.py后缀的。
关于模块更详细的讲解见之前的博客:
https://www.cnblogs.com/bytesfly/p/python.html#模块
python -m 常见用法
- 使用
cProfile模块分析程序函数调用链耗时
python -m cProfile -s cumulative bytesfly/fly.py
- 使用
pdb模块以调试模式来执行Python脚本
python -m pdb bytesfly/fly.py
- 使用
http.server模块实现一个简单的HTTP服务
python -m http.server 9000
- 使用
pydoc模块生成HTML格式的官方帮助文档,可以在浏览器中访问
python -m pydoc -p 9001
- python -m pip install xxx
在存在多个Python版本的环境中,这种写法可以精确地控制三方库的安装位置。例如用python3.8 -m pip,可以明确指定给3.8版本安装,而不会混淆成其它的版本。
当然现在我们大多使用conda之类的虚拟环境管理器和包管理器,可能不会出现上面所说的这种混淆情况。这里只是提一下。
- 使用
timeit模块分析执行耗时
python -m timeit -n 3 -r 2 "import time;time.sleep(1)"
其实调用的是:
timeit.repeat("import time;time.sleep(1)", repeat=2, number=3)
看一眼timeit.py中的源码就能快速理解-n -r参数的意思:
def repeat(self, repeat=default_repeat, number=default_number):
"""Call timeit() a few times.
This is a convenience function that calls the timeit()
repeatedly, returning a list of results. The first argument
specifies how many times to call timeit(), defaulting to 5;
the second argument specifies the timer argument, defaulting
to one million.
"""
r = []
for i in range(repeat):
t = self.timeit(number)
r.append(t)
return r
-p/--process: use time.process_time() (default is time.perf_counter())
timeit后面还能添加-p参数,如下:
python -m timeit -p -n 3 -r 2 "import time;time.sleep(1)"
其实调用的是:
timeit.repeat("import time;time.sleep(1)", repeat=2, number=3, timer=time.process_time)
再看一眼time.process_time()的代码注释
def process_time(): # real signature unknown; restored from __doc__
"""
process_time() -> float
Process time for profiling: sum of the kernel and user-space CPU time.
"""
return 0.0
加上了-p参数计算的是sum of the kernel and user-space CPU time,讲白了就是程序占用CPU的时间,程序睡眠或者请求网络IO阻塞的时间不算。
python -m 原理解析
看了上面python -m几种常见用法,你是否好奇python -m到底做了什么事?
不卖关子,一句话解释就是:
对于
python -m module_name,Python会检索sys.path,查找名字为module_name的模块或者包,并将其内容当成主程序入口来执行,换句话说在执行时,该脚本的__name__是__main__。
拿文章开篇的bytesfly.fly模块来说,也就是bytesfly包下的fly.py文件内容如下:
import sys
print("----fly----")
if __name__ == '__main__':
print("fly_main")
print(sys.path)
在hello项目路径下执行python -m bytesfly.fly,输出如下:
----fly----
fly_main
['/home/bytesfly/py/hello', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
如果直接执行呢? 即相同路径下执行python bytesfly/fly.py,输出如下:
----fly----
fly_main
['/home/bytesfly/py/hello/bytesfly', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
总结一下,python -m module_name与python folder/file.py,都会把定位到的Python脚本当成主程序入口来执行,即在执行时,该脚本的__name__都是__main__,与import导入模块不同。
但是有注意到上面两种调用方式的不同之处吗?
fly.py程序输出了sys.path,可以看到两种调用方式的Python Path有区别,这种区别有什么影响呢?
再看一个例子。 比如一个顶层包名还是bytesfly,按照如下目录存放:
bytesfly
├─ __init__.py
├─ __main__.py
└─ fly.py
└─ a
├─ __init__.py
└─ run.py
└─ b
├─ __init__.py
└─ tool.py
其中tool.py内容如下:
def add(a, b):
return a + b
其中run.py内容如下:
import sys
print(sys.path)
if __name__ == '__main__':
from bytesfly.b import tool
print(tool.add(1, 2))
同样在hello项目路径下执行python -m bytesfly.a.run,输出如下:
['/home/bytesfly/py/hello', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
3
然后在hello项目路径下执行python bytesfly/a/run.py,输出如下:
['/home/bytesfly/py/hello/bytesfly/a', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
Traceback (most recent call last):
File "bytesfly/a/run.py", line 6, in <module>
from bytesfly.b import tool
ModuleNotFoundError: No module named 'bytesfly'
这个地方能Get到这两种调用方式在Python Path上的区别?
除此之外,python -m module_name与python folder/file.py,在实现上有什么不同呢?
- 使用
python -m module_name,解释器在不import模块的情况下,在所有模块命名空间中查找,定位到脚本的路径,然后执行。为了实现这个过程,解释器会借助两个模块:pkgutil和runpy,前者用于获取所有的模块列表,后者根据模块名来定位并执行脚本 - 直接运行脚本时,相当于给出了脚本的完整路径(不管是绝对路径还是相对路径),解释器根据文件系统的查找机制,定位到该脚本,然后执行
python -m 补充说明
python -m module_name这里的module_name也可以是包名。
还是用上面的顶层包名bytesfly举例,按照如下目录存放:
bytesfly
├─ __init__.py
├─ __main__.py
└─ fly.py
└─ a
├─ __init__.py
└─ run.py
└─ b
├─ __init__.py
└─ tool.py
其中__main__.py内容如下:
import sys
print("---bytesfly---")
if __name__ == '__main__':
print(sys.path)
项目路径下执行python -m bytesfly,输出如下:
---bytesfly---
['/home/bytesfly/py/hello', '/home/bytesfly/anaconda3/envs/test/lib/python38.zip']
如果执行python -m bytesfly.a,输出如下:
No module named bytesfly.a.__main__; 'bytesfly.a' is a package and cannot be directly executed
原来,python -m bytesfly等效于python -m bytesfly.__main__。
写在最后
有了python -m module_name选项,在命令行中使用内置模块、标准包与第三方模块更加方便。
参考:
https://www.cnblogs.com/pythonista/p/11829632.html
https://www.cnblogs.com/xueweihan/p/5118222.html
python -m详解的更多相关文章
- Python闭包详解
Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...
- [转] Python Traceback详解
追莫名其妙的bugs利器-mark- 转自:https://www.jianshu.com/p/a8cb5375171a Python Traceback详解 刚接触Python的时候,简单的 ...
- python 数据类型详解
python数据类型详解 参考网址:http://www.cnblogs.com/linjiqin/p/3608541.html 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8 ...
- Python 递归函数 详解
Python 递归函数 详解 在函数内调用当前函数本身的函数就是递归函数 下面是一个递归函数的实例: 第一次接触递归函数的人,都会被它调用本身而搞得晕头转向,而且看上面的函数调用,得到的结果会 ...
- python线程详解
#线程状态 #线程同步(锁)#多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题. #threading模块#常用方法:'''threadin ...
- python数据类型详解(全面)
python数据类型详解 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8.字典9.日期 1.字符串1.1.如何在Python中使用字符串a.使用单引号(')用单引号括起来表示字 ...
- Python Collections详解
Python Collections详解 collections模块在内置数据结构(list.tuple.dict.set)的基础上,提供了几个额外的数据结构:ChainMap.Counter.deq ...
- python生成器详解
1. 生成器 利用迭代器(迭代器详解python迭代器详解),我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记 ...
- 转 python数据类型详解
python数据类型详解 目录 1.字符串 2.布尔类型 3.整数 4.浮点数 5.数字 6.列表 7.元组 8.字典 9.日期 1.字符串 1.1.如何在Python中使用字符串 a.使用单引号(' ...
- python多线程详解
目录 python多线程详解 一.线程介绍 什么是线程 为什么要使用多线程 二.线程实现 threading模块 自定义线程 守护线程 主线程等待子线程结束 多线程共享全局变量 互斥锁 递归锁 信号量 ...
随机推荐
- 【LeetCode】90. Subsets II 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 回溯法 日期 题目地址:https://leet ...
- 1421 最大MOD值
1421 最大MOD值 基准时间限制:1 秒 空间限制:131072 KB 有一个a数组,里面有n个整数.现在要从中找到两个数字(可以是同一个) ai,aj ,使得 ai mod aj 最大并且 a ...
- 永中dcs实现浏览器上面的手绘效果
永中dcs是一款在线预览各种办公文件的网络产品,我们可以只用一个浏览器就可以实现对word,ppt和excel等文件的在线浏览,在其中有一个在线手绘功能很有特色,让我们来探一探它的实现原理吧. 第一, ...
- uniapp中使用animate.css4.1.1动画库在小程序中不生效解决办法
找到源码animate.css修改以下代码 :root { --animate-duration: 1s; --animate-delay: 1s; --animate-repeat: 1; } // ...
- JDK Httpclient 使用和性能测试
Httpclient 使用和性能测试 上篇,通过简介和架构图,我们对HttpClient有了初步的了解. 本篇我们展示HttpClient的简单使用,同时为了说明httpclient的使用性能,我们将 ...
- Java程序设计基础笔记 • 【第5章 循环结构】
全部章节 >>>> 本章目录 5.1 while循环结构 5.1.1 循环简介 5.1.2 while循环 5.1.3 while循环的使用 5.1.4 while循环的注 ...
- MySQL数据操作与查询笔记 • 【第5章 MySQL 函数】
全部章节 >>>> 本章目录 5.1 数学函数和控制流函数 5.1.1 数学函数 5.1.2 控制流函数 5.2 字符串函数 5.2.1 字符串函数介绍 5.2.2 字符串 ...
- 简单的制作ssl证书,并在nginx和IIS中使用
2020年最后一篇博文收官,提前祝各位园友新年快乐 现在的后端开发,动不动就是需要https,或者说是需要ssl证书,既然没有正版的证书,那么我们只能自己制作ssl的证书了. 说明:证书的制作采用的是 ...
- POJ 2442 Sequence堆 优先队列
题目描述 给定m个序列,每个序列包含n个非负整数.现在我们可以从每个序列中选择一个数字以形成一个具有m个整数的序列.显然,我们可以得到n ^ m种这种序列.然后,我们可以计算每个序列中的数字总和,并获 ...
- 初识python:高阶函数(附-高阶函数)
定义: 变量可以指向函数,函数的参数能接收变量,那么,一个函数可以接收另一个函数作为参数,这种函数就称之为高阶函数. 简单说就是:把函数当作参数传递的函数就是高阶函数 特性 1.把一个函数名当作实参传 ...