跳转到主要内容

修复Python的破损__name__ == '__main__'行为的例程。

项目描述

此包为以下情况提供了一个干净的解决方案:您想编写一个可以从命令行安全调用的Python模块,但同时也需要被其他模块导入。只需将每个通常进行__name__ == '__main__'检查的模块这样写

'Your module docstring'

import demain
__main__ = demain.fix()

# Your other import statements
# Your classes and functions

if __main__:
    # Your code that gets invoked from the command line

在您的模块只是被另一个模块导入的情况下,fix()函数不执行任何操作并返回False。但如果您的模块被直接调用,无论是作为脚本还是使用Python的-m选项,则fix()

  • 将您的模块的__name__全局变量替换为其真实名称。

  • sys.modules中重新注册您的模块,使用其真实名称,以便其他Python模块稍后的导入语句可以找到它。

  • 如果您的模块位于包之下,则该模块将使用其正确名称插入到包中。

  • 在这些更正之后,该函数返回True,以便您的模块可以检测到它正在作为主程序运行。

我主张Python的将来版本完全停止更改模块名称,而是像demain一样在每个模块中设置一个__main__布尔值。但在那时之前,请使用demain为您的程序带来一些理智、安全,并减少神秘的中断和错误消息。

背景

当您从命令行运行Python脚本或使用-m选项调用模块时,Python会给该脚本或模块一个假名字'__main__',以便它能检测到它正在作为“主程序”运行。考虑一个看起来像这样的小脚本:

# foo.py
print __name__

从命令行调用它将破坏它原本的正常名称foo(我们可以通过从命令行导入该模块来证明这一点)

$ python foo.py
__main__
$ python -m foo
__main__
$ python -c 'import foo'
foo

当与本身也是导入目标的模块一起使用时,这种名称混淆会带来无穷无尽的麻烦,因为第一次尝试用其真实名称导入模块会导致创建一个模块的副本,其中包含其自己的每个对象和类的副本。这种错误通常特别难以追踪。

demain.fix()函数旨在通过在所有打算直接调用的模块顶部首先调用它来防止这种问题开始,要小心不要在运行fix()之前执行其他导入,还要确保不要首先创建任何类;否则,名称'__main__'将被复制到您的类中,作为它们模块的名称。

当我读到《捍卫Pyramid的设计》并读到Chris McDonough在标题为“应用程序程序员无法控制模块作用域代码路径”部分中的痛苦呼吁时,我知道我最终必须对此问题采取行动。

http://docs.pylonshq.com/pyramid/dev/designdefense.html

在那里,他丰富的Python经验和精炼的编码实践使他提出了一些非常出色的建议,反对小型Python应用程序(尤其是那些使用Web微框架编写的应用程序)在将脚本视为正常模块时所承担的风险。我希望demain通过将调用的Python脚本变成一个安全的地方来存放对象,而不是在应用程序的其它地方使用正常导入时将所有对象都复制。

此包附带一个适度的小型测试套件,由一些手建的示例和McDonough的样本装饰器框架组成,该框架展示了Python处理脚本调用的问题。要运行它,只需输入:

$ python -m demain.tests

项目详情


下载文件

下载适合您平台的自定义文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。

源分布

demain-0.9.tar.gz (4.4 kB 查看散列)

上传时间

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面