涨见识了,在终端执行 Python 代码的 6 种方式
off999 2024-09-29 16:20 35 浏览 0 评论
原作:BRETT CANNON
译者:豌豆花下猫@Python猫
英文:https://snarky.ca/the-many-ways-to-pass-code-to-python-from-the-terminal
为了我们推出的 VS Code 的 Python 插件 [1],我写了一个简单的脚本来生成变更日志 [2](类似于Towncrier [3],但简单些,支持 Markdown,符合我们的需求)。在发布过程中,有一个步骤是运行python news ,它会将 Python 指向我们代码中的"news"目录。
前几天,一位合作者问这是如何工作的,似乎我们团队中的每个人都知道如何使用-m ?(请参阅我的有关带 -m 使用 pip 的文章 [4],了解原因)(译注:关于此话题,我也写过一篇更为详细的文章 )
这使我意识到其他人可能不知道有五花八门的方法可以将 Python 指向要执行的代码,因此有了这篇文章。
1、通过标准输入和管道
因为如何用管道传东西给一个进程是属于 shell 的内容,我不打算深入解释。毋庸置疑,你可以将代码传递到 Python 中。
# 管道传内容给 python
echo "print('hi')" | python
如果将文件重定向到 Python,这显然也可以。
# 重定向一个文件给 python
python < spam.py
归功于 Python 的 UNIX 传统,这些都不太令人感到意外。
2、通过`-c` 指定的字符串
如果你只需要快速地检查某些内容,则可以在命令行中将代码作为字符串传递。
# 使用 python 的 -c 参数
python -c "print('hi')"
当需要检查仅一行或两行代码时,我个人会使用它,而不是启动 REPL(译注:Read Eval Print Loop,即交互式解释器,例如在 windows 控制台中输入python, 就会进入交互式解释器。-c 参数用法可以省去进入解释器界面的过程) 。
3、文件的路径
最众所周知的传代码给 python 的方法很可能是通过文件路径。
# 指定 python 的文件路径
python spam.py
要实现这一点的关键是将包含该文件的目录放到sys.path 里。这样你的所有导入都可以继续使用。但这也是为什么你不能/不应该传入包含在一个包里的模块路径。因为sys.path 可能不包含该包的目录,因此所有的导入将相对于与你预期的包不同的目录。
4、对包使用 -m
执行 Python 包的正确方法是使用 -m 并指定要运行的包名。
python -m spam
它在底层使用了runpy [5]。要在你的项目中做到这点,只需要在包里指定一个__main__.py 文件,它将被当成__main__ 执行。而且子模块可以像任何其它模块一样导入,因此你可以对其进行各种测试。
我知道有些人喜欢在一个包里写一个main 子模块,然后将其__main__.py 写成:
from . import main
if __name__ == "__main__":
main.main()
就我个人而言,我不感冒于单独的main 模块,而是直接将所有相关的代码放入__main__.py ,因为我感觉这些模块名是多余的。
(译注:即作者不关心作为入口文件的"main"或者“__main__”模块,因为执行时只需用它们的包名即可。我认为这也暗示了入口模块不该再被其它模块 import。我上篇文章 [6]比作者的观点激进,认为连那句 if 语句都不该写。)
5、目录
定义__main__.py也可以扩展到目录。如果你看一下促成此博客文章的示例,python news 可执行,就是因为 news 目录有一个 __main__.py 文件。该目录就像一个文件路径被 Python 执行了。
现在你可能会问:“为什么不直接指定文件路径呢?”好吧,坦白说,关于文件路径,有件事得说清楚。在发布过程中,我可以简单地写上说明,让运行python news/announce.py ,但是并没有确切的理由说明这种机制何时存在。
再加上我以后可以更改文件名,而且没人会注意到。再加上我知道代码会带有辅助文件,因此将其放在目录中而不是单独作为单个文件是有意义的。
当然,我也可以将它变为一个使用 -m 的包,但是没必要,因为 announce 脚本很简单,我知道它要保持成为一个单独的自足的文件(少于 200 行,并且测试模块也大约是相同的长度)。
况且,__main__.py 文件非常简单。
import runpy
# Change 'announce' to whatever module you want to run.
runpy.run_module('announce', run_name='__main__', alter_sys=True)
现在显然必须要处理依赖关系,但是如果你的脚本仅使用标准库或将依赖模块放在__main__.py 旁边(译注:即同级目录),那么就足够了!
(译注:我觉得作者在此有点“炫技”了,因为这种写法的前提是得知道 runpy 的用法,但是就像前一条所写的用 -m 参数运行一个包,在底层也是用了 runpy。不过炫技的好处也非常明显,即__main__.py 里不用导入 announce 模块,还是以它为主模块执行,也就不会破坏原来的依赖导入关系)
6、执行一个压缩文件
如果你确实有多个文件和/或依赖模块,并且希望将所有代码作为一个单元发布,你可以用一个__main__.py ,放置在一个压缩文件中,并把压缩文件所在目录放在 sys.path 里,Python 会替你运行__main__.py 文件。
# 将一个压缩包传给 Python
python app.pyz
人们现在习惯上用 .pyz 文件扩展名来命名此类压缩文件,但这纯粹是传统,不会影响任何东西;你当然也可以用 .zip 文件扩展名。
为了简化创建此类可执行的压缩文件,标准库提供了zipapp [7]模块。它会为你生成__main__.py并添加一条组织行(shebang line),因此你甚至不需要指定 python,如果你不想在 UNIX 上指定它的话。如果你想移动一堆纯 Python 代码,这是一种不错的方法。
不幸的是,仅当压缩文件包含的所有代码都是纯 Python 时,才能这样运行压缩文件。执行压缩文件对扩展模块无效(这就是为什么 setuptools 有一个 zip_safe [8]标志的原因)。(译注:扩展模块 extension module,即 C/C++ 之类的非 Python 文件)
要加载扩展模块,Python 必须调用 dlopen() [9]函数,它要传入一个文件路径,但当该文件路径就包含在压缩文件内时,这显然不起作用。
我知道至少有一个人与 glibc 团队交谈过,关于支持将内存缓冲区传入压缩文件,以便 Python 可以将扩展模块读入内存,并将其传给压缩文件,但是如果内存为此服务,glibc 团队并不同意。
但是,并非所有希望都丧失了!你可以使用诸如shiv [10]之类的项目,它会捆绑(bundle)你的代码,然后提供一个__main__.py 来处理压缩文件的提取、缓存,然后为你执行代码。尽管不如纯 Python 解决方案理想,但它确实可行,并且在这种情况下算得上是优雅的。
(译注:翻译水平有限,难免偏差。我加注了部分内容,希望有助于阅读。请搜索关注“Python猫”,阅读更多优质的原创或译作。)
参考链接
[0] https://snarky.ca/the-many-ways-to-pass-code-to-python-from-the-terminal/
[1] https://marketplace.visualstudio.com/items?itemName=ms-python.python
[2] https://github.com/microsoft/vscode-python/tree/master/news
[3] https://pypi.org/project/towncrier
[4] https://snarky.ca/why-you-should-use-python-m-pip
[5] https://docs.python.org/3/library/runpy.html#module-runpy
[6] https://mp.weixin.qq.com/s/1ehySR5NH2v1U8WIlXflEQ
[7] https://docs.python.org/3/library/zipapp.html#module-zipapp
[8] https://setuptools.readthedocs.io/en/latest/setuptools.html#setting-the-zip-safe-flag
[9] https://linux.die.net/man/3/dlopen
[10] https://pypi.org/project/shiv/
相关推荐
- apisix动态修改路由的原理_动态路由协议rip的配置
-
ApacheAPISIX能够实现动态修改路由(DynamicRouting)的核心原理,是它将传统的静态Nginx配置彻底解耦,通过中心化配置存储(如etcd)+OpenRest...
- 使用 Docker 部署 OpenResty Manager 搭建可视化反向代理系统
-
在之前的文章中,xiaoz推荐过可视化Nginx反向代理工具NginxProxyManager,最近xiaoz还发现一款功能更加强大,界面更加漂亮的OpenRestyManager,完全可以替代...
- OpenResty 入门指南:从基础到动态路由实战
-
一、引言1.1OpenResty简介OpenResty是一款基于Nginx的高性能Web平台,通过集成Lua脚本和丰富的模块,将Nginx从静态反向代理转变为可动态编程的应用平台...
- OpenResty 的 Lua 动态能力_openresty 动态upstream
-
OpenResty的Lua动态能力是其最核心的优势,它将LuaJIT嵌入到Nginx的每一个请求处理阶段,使得开发者可以用Lua脚本动态控制请求的生命周期,而无需重新编译或rel...
- LVS和Nginx_lvs和nginx的区别
-
LVS(LinuxVirtualServer)和Nginx都是常用的负载均衡解决方案,广泛应用于大型网站和分布式系统中,以提高系统的性能、可用性和可扩展性。一、基本概念1.LVS(Linux...
- 外网连接到内网服务器需要端口映射吗,如何操作?
-
外网访问内网服务器通常需要端口映射(或内网穿透),这是跨越公网与私网边界的关键技术。操作方式取决于网络环境,以下分场景详解。一、端口映射的核心原理内网服务器位于私有IP地址段(如192.168.x.x...
- Nginx如何解决C10K问题(1万个并发连接)?
-
关注△mikechen△,十余年BAT架构经验倾囊相授!大家好,我是mikechen。Nginx是大型架构的必备中间件,下面我就全面来详解NginxC10k问题@mikechen文章来源:mikec...
- 炸场!Spring Boot 9 大内置过滤器实战手册:从坑到神
-
炸场!SpringBoot9大内置过滤器实战手册:从坑到神在Java开发圈摸爬滚打十年,见过太多团队重复造轮子——明明SpringBoot自带的过滤器就能解决的问题,偏偏要手写几十...
- WordPress和Typecho xmlrpc漏洞_wordpress主题漏洞
-
一般大家都关注WordPress,毕竟用户量巨大,而国内的Typecho作为轻量级的博客系统就关注的人并不多。Typecho有很多借鉴WordPress的,包括兼容的xmlrpc接口,而WordPre...
- Linux Shell 入门教程(六):重定向、管道与命令替换
-
在前几篇中,我们学习了函数、流程控制等Shell编程的基础内容。现在我们来探索更高级的功能:如何控制数据流向、将命令链接在一起、让命令间通信变得可能。一、输入输出重定向(>、>>...
- Nginx的location匹配规则,90%的人都没完全搞懂,一张图让你秒懂
-
刚配完nginx网站就崩了?运维和开发都头疼的location匹配规则优先级,弄错顺序直接导致500错误。核心在于nginx处理location时顺序严格:先精确匹配=,然后前缀匹配^~,接着按顺序正...
- liunx服务器查看故障命令有那些?_linux查看服务器性能命令
-
在Linux服务器上排查故障时,需要使用一系列命令来检查系统状态、日志文件、资源利用情况以及网络状况。以下是常用的故障排查命令,按照不同场景分类说明。1.系统资源相关命令1.1查看CPU使...
- 服务器被入侵的常见迹象有哪些?_服务器入侵可以被完全操纵吗
-
服务器被入侵可能会导致数据泄露、服务异常或完全失控。及时发现入侵迹象能够帮助你尽早采取措施,减少损失。以下是服务器被入侵的常见迹象以及相关的分析与处理建议。1.服务器被入侵的常见迹象1.1系统性能...
- 前端错误可观测最佳实践_前端错误提示
-
场景解析对于前端项目,生产环境的代码通常经过压缩、混淆和打包处理,当代码在运行过程中产生错误时,通常难以还原原始代码从而定位问题,对于深度混淆尤其如此,因此Mozilla自2011年开始发起并...
- 8个能让你的Kubernetes集群“瞬间崩溃”的配置错误
-
错误一:livenessProbe探针“自杀式”配置——30秒内让Pod重启20次现象:Pod状态在Running→Terminating→CrashLoopBackOff之间循环,重启间隔仅...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- apisix动态修改路由的原理_动态路由协议rip的配置
- 使用 Docker 部署 OpenResty Manager 搭建可视化反向代理系统
- OpenResty 入门指南:从基础到动态路由实战
- OpenResty 的 Lua 动态能力_openresty 动态upstream
- LVS和Nginx_lvs和nginx的区别
- 外网连接到内网服务器需要端口映射吗,如何操作?
- Nginx如何解决C10K问题(1万个并发连接)?
- 炸场!Spring Boot 9 大内置过滤器实战手册:从坑到神
- WordPress和Typecho xmlrpc漏洞_wordpress主题漏洞
- Linux Shell 入门教程(六):重定向、管道与命令替换
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)