前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最全总结:把模块当做脚本来执行的 7 种案例及其原理

最全总结:把模块当做脚本来执行的 7 种案例及其原理

作者头像
Python进阶者
发布2020-09-22 11:28:16
4160
发布2020-09-22 11:28:16
举报

本篇选自 Python黑魔法指南 -> 第二章 -> 第14节

github仓库: https://github.com/iswbm/magic-python

如本文对你有用,可否到 github 上帮我点个 star 呢?


1. 用法举例

前面的文章里其实分享过不少类似的用法。比如:

1、 快速搭建一个 HTTP 服务

代码语言:javascript
复制
# python2
$ python -m SimpleHTTPServer 8888

# python3
$ python3 -m http.server 8888

效果如下:

2、快速构建 HTML 帮助文档

代码语言:javascript
复制
$ python -m pydoc -p 5200

效果如下:

3、快速进入 pdb 调试模式

代码语言:javascript
复制
$ python -m pdb demo.py

4、最优雅且正确的包安装方法

代码语言:javascript
复制
$ python3 -m pip install requests

5、快速美化 JSON 字符串

代码语言:javascript
复制
$ echo '{"name": "MING"}' | python -m json.tool

6、快速打印包的搜索路径

代码语言:javascript
复制
$ python -m site

效果如下:

7、用于快速计算程序执行时长

代码语言:javascript
复制
$ python3 -m timeit '"-".join(map(str, range(100)))'

2. 原理剖析

上面的诸多命令,都有一个特点,在命令中都含有 -m 参数选项,而参数的值,SimpleHTTPServer, http.server, pydoc,pdb,pip, json.tool,site ,timeit这些都是模块或者包。

通常来说模块或者包,都是用做工具包由其他模块导入使用,而很少直接使用命令来执行(脚本除外)。

Python 给我们提供了一种方法,可以让我们将模块里的部分功能抽取出来,直接用于命令行式的调用。效果就是前面你所看到的。

那这是如何实现的呢?

最好的学习方式,莫过于模仿,直接以 pip 和 json 模块为学习对象,看看目录结构和代码都有什么特点。

先看一下 pip 的源码目录,发现在其下有一个 __main__.py 的文件,难道这是 -m 的入口?

再看一下 json.tool 的源码文件,json 库下面却没有 __main__.py 的文件。

这就很奇怪了。

不对,再回过头看,我们调用的不是 json 库,而是 json 库下的 tool 模块。

查看 tool 模块的源代码,有一个名为 main 的函数

但它这不是关键,main 函数是在模块中直接被调用的。

只有当 __name____main___ 时,main 函数才会被调用

代码语言:javascript
复制
if __name__ == '__main__':
    main()

当模块被导入时,__name__ 的值为模块名,

而当模块被直接执行,__name__ 的值就变成了 __main__

这下思路清晰了,我来总结一下:

想要使用 -m 的方式执行模块,有两种方式:

  • 第一种:以 -m <package> 的方式执行,只要在 package 下写一个 __main__.py 的文件即可。
  • 第二种:以 -m <package.module> 的方式执行,只要在 module 的代码中,定义一个 main 函数,然后在最外层写入下面这段固定的代码
代码语言:javascript
复制
if __name__ == '__main__':
    main()

上面我将 -m 的使用情况分为两种,但是实际上,只有一种,对于第一种,你完全可以将 -m <package> 理解为 -m <package.__main__> 的简写形式。

3. 实践一下

先把当前路径设置追加到 PATH 的环境变量中

代码语言:javascript
复制
$ export PATH=${PATH}:`pwd`

先来验证一下第一种方法。

然后在当前目录下新建一个demo 文件夹,并且在 demo 目录下新建一个 __main__.py 的文件,随便打印点东西

代码语言:javascript
复制
# __main__.py
print("hello, world")

然后直接执行如下命令,立马就能看到效果。

代码语言:javascript
复制
$ python3 -m demo
hello,world

执行过程如下:

再来验证一下使用第二种方法。

在 demo 目录下再新建一个 foobar.py 文件

代码语言:javascript
复制
# foobar.py
def main():
    print("hello, world")

if __name__ == "__main__":
    main()

最后执行一下如下命令,输出与预期相符

代码语言:javascript
复制
$ python3 -m demo.foobar
hello, foobar

4. -m 存在的意义

-m 实现的效果,无异于直接执行一个 Python 模块/脚本。

那么问题就来了,那我直接执行不就行啦,何必多此一举再加个 -m 呢?

这个问题很有意思,值得一提。

当我们使用一个模块的时候,往往只需要记住模块名,然后使用 import 去导入它就行了。

之所以能这么便利,这得益于 Python 完善的导入机制,你完全不需要知道这个模块文件存在哪个目录下,它的绝对路径是什么?因为 Python 的包导入机制会帮你做这些事情。

换句话说,如果你不使用 -m 的方式,当你要使用 python -m json.tool,你就得这样子写

代码语言:javascript
复制
$ echo '{"name": "MING"}' | python /usr/lib64/python2.7/json/tool.py
{
    "name": "MING"
}

如此一对比,哪个更方便?你心里应该有数了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python爬虫与数据挖掘 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 用法举例
  • 2. 原理剖析
  • 3. 实践一下
  • 4. -m 存在的意义
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档