python 根据类名 查找module_关于 Python 命令中的 m 参数

在命令行中使用 Python 时,它可以接收大约 20 个选项(option),语法格式如下:
python [-bBdEhiIOqsSuvVWx?] [-c command | -m module-name | script | - ] [args]

本文想要聊聊比较特殊的“-m”选项:关于它的典型用法、原理解析与发展演变的过程。

首先,让我们用“--help”来看看它的解释:

1352ee4f8b4f47083fe0eb350e860ff7.png

-m  mod run library module as a script (terminates option list)

"mod"是“module”的缩写,即“-m”选项后面的内容是 module(模块),其作用是把模块当成脚本来运行。

“terminates option list”意味着“-m”之后的其它选项不起作用,在这点上它跟“-c”是一样的,都是“终极选项”。官方把它们定义为“接口选项”(Interface options),需要区别于其它的普通选项或通用选项。

-m 选项的五个典型用法

Python 中有很多使用 -m 选项的场景,相信大家可能会用到或者看见过,我在这里想分享 5 个。

在 Python3 中,只需一行命令就能实现一个简单的 HTTP 服务:

python -m http.server 8000

# 注:在 Python2 中是这样
python -m SimpleHTTPServer 8000
9e23fd8e527a55f0c4168526178c5715.png

执行后,在本机打开“http://localhost:8000”,或者在局域网内的其它机器上打开“http://本机ip:8000”,就能访问到执行目录下的内容,例如下图就是我本机的内容:

50a78ebdc0126b9522621961ce378dc5.png

与此类似,我们只需要一行命令“python -m pydoc -p xxx”,就能生成 HTML 格式的官方帮助文档,可以在浏览器中访问。

41f15a61bd3f4ba61b2859aca3ef42bb.png

上面的命令执行了 pydoc 模块,会在 9000 端口启动一个 http 服务,在浏览器中打开,我的结果如下:

06622187951fe2b53212d897b51b5060.png

它的第三个常见用法是执行 pdb 的调试命令“python -m pdb xxx.py”,以调试模式来执行“xxx.py”脚本:

35992c77ed10a472d5c9cbe609952ca4.png

第四个同样挺有用的场景是用 timeit 在命令行中测试一小段代码的运行时间。以下的 3 段代码,用不同的方式拼接 “0-1-2-……-99” 数字串。可以直观地看出它们的效率差异:

ed7d40d15eff322af800811a675a9e01.png

最后,还有一种常常被人忽略的场景:“python -m pip install xxx”。我们可能会习惯性地使用“pip install xxx”,或者做了版本区分时用“pip3 install xxx”,总之不在前面用“python -m”做指定。但这种写法可能会出问题。

很巧合的是,在本月初(2019.11.01),Python 的核心开发者、第一届指导委员会五人成员之一的 Brett Cannon 专门写了一篇博客《Why you should use "python -m pip"》,提出应该使用“python -m pip”的方式,并做了详细的解释。

他的主要观点是:在存在多个 Python 版本的环境中,这种写法可以精确地控制三方库的安装位置。例如用“python3.8 -m pip”,可以明确指定给 3.8 版本安装,而不会混淆成其它的版本。

(延伸阅读:关于 Brett 的文章,这有一篇简短的归纳《原来我一直安装 Python 库的姿势都不对呀!》)

-m 选项的两种原理解析

看了前面的几种典型用法,你是否开始好奇:“-m”是怎么运作的?它是怎么实现的?

对于“python -m name”,一句话解释:Python 会检索sys.path ,查找名字为“name”的模块或者包(含命名空间包),并将其内容当成“__main__”模块来执行。

1、对于普通模块

以“.py”为后缀的文件就是一个模块,在“-m”之后使用时,只需要使用模块名,不需要写出后缀,但前提是该模块名是有效的,且不能是用 C 语言写成的模块。

在“-m”之后,如果是一个无效的模块名,则会报错“No module named xxx”。

如果是一个带后缀的模块,则首先会导入该模块,然后可能报错:Error while finding module specification for 'xxx.py' (AttributeError: module 'xxx' has no attribute '__path__'。

dca4fe85b40252fcac99f2b7230ad007.png

对于一个普通模块,有时候这两种写法表面看起来是等效的:

fcc0614e5ccd8de9b5c06713bfe8b301.png

两种写法都会把定位到的模块脚本当成主程序入口来执行,即在执行时,该脚本的__name__都是”__main__“,跟 import 导入方式是不同的。

但它的前提是:在执行目录中存在着“test.py”,且只有唯一的“test”模块。对于本例,如果换一个目录执行的话,“python test.py”当然会报找不到文件的错误,然而,“python -m test”却不会报错,因为解释器在遍历sys.path时可以找到同名的“test”模块,并且执行:

d2c4839e6b57d4f25bb84107546dae4d.png

由此差异,我们其实可以总结出“-m”的用法:已知一个模块的名字,但不知道它的文件路径,那么使用“-m”就意味着交给解释器自行查找,若找到,则当成脚本执行。

以前文的“python -m http.server 8000”为例,我们也可以找到“server”模块的绝对路径,然后执行,尽管这样会变得很麻烦。

62dad9e86e407ffb3bda4903870e0ba3.png

那么,“-m”方式与直接运行脚本相比,在实现上有什么不同呢?

  • 直接运行脚本时,相当于给出了脚本的完整路径(不管是绝对路径还是相对路径),解释器根据文件系统的查找机制, 定位到该脚本,然后执行
  • 使用“-m”方式时,解释器需要在不 import 的情况下,在所有模块命名空间 中查找,定位到脚本的路径,然后执行。为了实现这个过程,解释器会借助两个模块:pkgutilrunpy,前者用来获取所有的模块列表,后者根据模块名来定位并执行脚本

2、对于包内模块

如果“-m”之后要执行的是一个包,那么解释器经过前面提到的查找过程,先定位到该包,然后会去执行它的“__main__”子模块,也就是说,在包目录下需要实现一个“__main__.py”文件。

换句话说,假设有个包的名称是“pname”,那么,“python -m pname”,其实就等效于“python -m pname.__main__”。

仍以前文创建 HTTP 服务为例,“http”是 Python 内置的一个包,它没有“__main__.py”文件,所以使用“-m”方式执行时,就会报错:No module named http.__main__; 'http' is a package and cannot be directly executed。

ca80ddc70e406f4bed6374e4a22bd74c.png

作为对比,我们可以看看前文提到的 pip,它也是一个包,为什么“python -m pip”的方式可以使用呢?当然是因为它有“__main__.py”文件:

8ca1dc1c8ec56b15fbc1558fb020dc36.png

“python -m pip”实际上执行的就是这个“__main__.py”文件,它主要作为一个调用入口,调用了核心的"pip._internal.main"。

http 包因为没有一个统一的入口模块,所以采用了“python -m 包.模块”的方式,而 pip 包因为有统一的入口模块,所以加了一个“__main__.py”文件,最后只需要写“python -m 包”,简明直观。

-m 选项的十年演变过程

最早引入 -m 选项的是 Python 2.4 版本(2004年),当时功能还挺受限,只能作用于普通的内置模块(如 pdb 和 profile)。

随后,知名开发者 Nick Coghlan 提出的《PEP 338 -- Executing modules as scripts》把它的功能提升了一个台阶。这个 PEP 在 2004 年提出,最终实现在 2006 年的 2.5 版本。

(插个题外话:Nick Coghlan 是核心开发者中的核心之一,也是第一届指导委员会的五人成员之一。记得当初看材料,他是在 2005 年被选为核心开发者的,这时间与 PEP-338 的时间紧密贴合)

3073f4fc1ed2920e1cb32071905c7287.png

这个 PEP 的几个核心点是:

  • 结合了 PEP-302 的新探针机制(new import hooks),提升了解释器查找包内模块的能力

  • 结合了其它的导入机制(例如zipimport和冻结模块(frozen modules)),拓展了解释器查找模块的范围与精度

  • 开发了新的runpy.run_module(modulename)来实现本功能,而不用修改 CPython 解释器,如此可方便移植到其它解释器

至此,-m 选项使得 Python 可以在所有的命名空间内定位到命令行中给定的模块。

2009 年,在 Python 3.1 版本中,只需给定包的名称,就能定位和运行它的“__main__”子模块。2014 年,-m 扩展到支持命名空间包。

至此,经过十年的发展演变,-m 选项变得功能齐全,羽翼丰满。

最后,我们来个 ending 吧:-m 选项可能看似不起眼,但它绝对是最特别的选项之一,它使得在命令行中,使用内置模块、标准包与三方库时变得更轻松便利。有机会就多用一下吧,体会它带来的愉悦体验。

参考材料

https://docs.python.org/3.7/using/cmdline.html#cmdoption-m

https://snarky.ca/why-you-should-use-python-m-pip

https://www.python.org/dev/peps/pep-0338

https://blog.csdn.net/jian3x/article/details/89556592

作者:豌豆花下猫 

来源:Python猫


6eafbff4abdecf0aa72f7b090a963529.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/498915.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php xampp bug,PHP网站访问慢的处理方法

如果网站跑在了LAMP环境中,就无法使用php-fpm的slow log了,那如何分析瓶颈点?没关系你还可以使用这个XdebugWebgrind,其中Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析…

matlab安装程序无法启动jvm_JVM 执行 Java 程序时的内存区域划分

在学习 Java 虚拟机(后面简称: JVM )中的垃圾回收机制(GC)之前,先需要了解 在 JVM 中的 Java 程序(class 文件)加载到内存之后到底是怎么存的。在阅读了 JVM规范 和周志明的 《深入理解Java虚拟机(第2版)》 之后,总结一下JVM中的内存划分以及…

phpFpm加载php,php-fpm添加service服务的例子

nginx通过FastCGI运行PHP比Apache包含PHP环境有明显的优势,最近有消息称,PHP5.4将很有可能把PHP-FPM补丁包含在内核里,nginx服务器平台上运行PHP将更加轻松,下面我们就来看一篇php-fpm平滑启动并配置服务例子。我的php是源码安装的。php-fpm在PHP 5.3.2以后的版本不支持以前的p…

python 性能问题_Python 性能问题一直饱受诟病,这篇我们讨论下提升 Python 应用性能的常见方法。...

Python - 提高Python运行效率的六个窍门Python是一门优秀的语言,它能让你在短时间内通过极少量代码就能完成许多操作。不仅如此,它还轻松支持多任务处理,比如多进程。不喜欢Python的人经常会吐嘈Python运行太慢。但是,事实并非如此…

php中没有dockerfile,Dockerfile在RUN composer install命令中没有使用缓...

我以为我已经理解了Docker,但今天我发现了一些关于利用docker缓存的问题.这是我的dockerfileFROM quay.io/my_company/phpjenkinsWORKDIR /usr/src/my_projectADD composer.json composer.jsonADD composer.lock composer.lockRUN composer install -oADD . .RUN mkdir -p temp…

map循环遍历取值_Collection集合框架集和map

Collection集合框架集Java培训之Collection集合框架集MapMap概述Map与Collection并列存在。用于保存具有映射关系的数据:Key-ValueMap 中的 key 和 value 都可以是任何引用类型的数据Map 中的 key 不允许重复key 和 value 之间存在单向一对一关系,即通过指定的 key …

php查询字段前30个字符,php/json我的字段名被截断为30个字符。我能停下来吗?

好吧,我得到了一个供应商软件,他们说应该在ApachePHP服务器和MySQL数据库上运行。我没有这两个,所以我把它放在一个php-iis服务器上,并将代码转换为在SQL服务器上工作。前任。mysql_select_db->mssql_select_db(除其他外)所以我在一个PHP文件中有以下代码$query "SELE…

rserve php,使用Rserve远程执行R脚本

Rserve介绍Rserve是一个基于TCP/IP协议的,允许R语言与其他语言通信的C/S结构的程序,支持C/C,Java,PHP,Python,Ruby,Nodejs等。 Rserve提供远程连接,认证,文件传输等功能。我们可以设计R做为后台服务,处理统计建模&…

搜索引擎提交软件_搜索引擎优化的发展史及SEO前景展望

SEO 是随着搜索引擎的普及而出现,并伴随搜索引擎的发展而发展的。关于搜索引擎和搜索引擎优化SEO 最初是怎么诞生的有很多种说法。有一个非常有趣的事实是,最早的一批SEO 甚至可以追溯到Yahoo 出现之前,我们可以把Yahoo 的传世人David Filo 和…

mongodb模糊查询_MongoDB的CRUD基本操作

原创:牛津小马哥Python后端工程师小李哥。在上周的推文中,我们介绍了MongoDB的数据库和集合的操作,现在,让我们来继续学习mongodb的另一个操作:CRUDCRUD操作:创建、读取、更新、删除文档。创建操作&#xf…

java有关问题,java经典有关问题!

java经典问题!!!问题一:与equal的区别?和 equals 都是比较的,而前者是运算符,后者则是一个方法,基本数据类型和引用数据类型都可以使用运算符,而只有引用类型数据才可以使用 equals,下面具体介绍一下两者的用法以及区别…

python怎么创业_python创业

从GitHub中整理出的15个最受欢迎的Python开源框架。这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等。Django:PythonWeb应用开发框架Django应该是最出名的Python框架,GAE甚至Erlang都有框架受…

python开发需要什么基础_零基础学习Python需要用什么开发工具?

对于学习Python的小伙伴,小编首推的Pycharm。首先,PyCharm用于一般IDE具备的功能,比如, 调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制另外,PyCharm还提供了一些很好的功能用于Djan…

php send helo/ehlo first错误,phpmailer发送邮件提示SMTP server error怎么回事?

以下是我的代码错误提示信息为:SMTP server error: Error: send HELO/EHLO first如果把SMTPAuth改为true,错误为SMTP Error: Could not authenticate. Mail errorSMTP Error: Could not authenticate.请教大神是什么原因?是不是还需要哪些设置…

python elasticsearch_python elasticsearch模块使用

加载模块from elasticsearch import Elasticsearch连接ESes Elasticsearch(["172.30.6.12"])查询res es.search(index"test-index", body{"query":{"match_all":{}}})# 查询请求主机是ai.baidu.com 所有信息res es.search(index&qu…

php ci model条件查询,php – CodeIgniter中的多条件WHERE子句

我想删除一些像核心PHP中的查询这样的数据WHERE user_id$id AND sender_id$send_id OR user_id$send_id AND sender_id$id所以我在CodeIgniter中尝试使用Active Record,如下所示:$this->db->where(user_id ,$id);$this->db->or_where(user_id ,$send_id…

python语言打印菱形_Python 实现打印单词的菱形字符图案

Python 实现打印单词的菱形字符图案我就废话不多说了,还是直接看代码吧!a [1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1]b [ * 2 * (7 - i) Good * i for i in a]for line in b:print(line)程序运行结果如下:补充知识:python打印菱…

java快捷键查看目录,java取得快捷方式指向的路径

当前位置:我的异常网 行业应用 java取得快捷方式指向的路径java取得快捷方式指向的路径www.myexceptions.net 网友分享于:2013-08-17 浏览:5次java获得快捷方式指向的路径import java.io.ByteArrayOutputStream;import java.io.File;import java.io.F…

python 编程算法_python语言编程算法

编程题1 台阶问题/斐波那契一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。fib lambda n: n if n < 2 else fib(n - 1) fib(n - 2)第二种记忆方法def memo(func):cache {}def wrap(*args):if args not in cache:cac…

php邮件中文乱码,phpmailer 发送邮件中文乱码问题的解决方法总结

$mail new PHPMailer();复制代码2&#xff1a;设置邮件的编码&#xff1b;$mail->CharsetUTF-8;复制代码相信有不少朋友是设置成"GBK"或“GB2312”的&#xff0c;我开始也是&#xff0c;后来了解到Mail是国际化的&#xff0c;如果想在像Gmail等那样的国际化邮箱正…