如何将模块用作包的一部分并作为可直接执行的脚本?

How to use a module as part of a package and as a directly executable script?

假设我有一个名为 my_package 的包文件夹。该目录包含一个名为 __init__.py 的文件和一个名为 my_module.py 的模块文件以及其他模块文件。模块 my_module.py 包含函数 do_something_with_file(file_path).

该函数在包的其他部分使用,但如果它可以作为命令行脚本调用,它将文件路径作为第一个位置参数并执行该函数,这将是实用的。我第一个天真的方法是通过以下方式实现:

if __name__ == "__main__":
    import sys
    do_something_with_file(sys.argv[1])

my_module.py 文件中。

但这需要 my_module.py 作为 main 执行。但作为包的一部分,它使用相对导入,只有当模块作为包的一部分执行时才有效,但如果脚本直接执行则失败,这使得这种方法没有吸引力。似乎此文件中的主块不是获得所需功能的正确方法。

将功能公开为简单脚本的最佳做法是什么?

我没有使用 python 打包的经验,我通常通过执行 python my_script.py 直接使用脚本,但我想更好地理解包和公开功能 with/via包。

如果您愿意公开一大堆模块以通过命令行使用,也许您可​​以创建一个 python 脚本,该脚本根据接收到的参数有条件地导入每个模块,而不必必须将 if __name__ == "__main__" 部分添加到它们中的每一个,以便您有一个脚本来调用多个模块。

如果您使软件包可安装,则公开脚本入口点效果最佳。我将尝试使用 python 本身附带的基本工具来提供一种或多或少的最小方法来做到这一点,并在最后列出一些第三方软件包,如果您有的话,它们会使整个过程更加愉快维护一段时间或者再写几个脚本。


要使用 setuptools 将您的代码转换为可安装的程序包,并使代码中的特定功能成为外部可执行脚本,请将 setup.py 文件添加到目录的顶层,像这样:

my_project
├───setup.py  # right here, next to your source-code folder
└───my_package
    ├───__init__.py 
    └───my_module.py

setup.py 的内容至少是这样(检查 here 以了解更多可能对您的项目有意义或可能没有意义的关键字):

import setuptools

setuptools.setup(
  name="my_package",        # your choice, but usually same as the package 
  version="0.1.0",          # obligatory
  packages=["my_package"],  # name of the folder relative to this file where the source code lives
  install_requires=[],      # your dependencies, if you have any
  entry_points = {          # this here is the magic that binds your function into a callable script
      'console_scripts': ['my_script=my_package.my_module:do_something_with_file'],
  }
)

entry_points'console_scripts' 键结合使用的格式是:

['my_script=my_package.my_module:do_something_with_file']
| |        | └─ this is essentially just a slightly reformatted import of
| |        |    'from my_package.my_module import do_something_with_file'
| |        └─ this sign starts the parsing of the lookup string for the bound function 
| └─ the name you want to call your script by, can be chosen freely
└─ a list, since you can install multiple scripts with a single package

一旦你的设置就位,你 运行 pip install -e . 在它旁边。现在你的代码作为一个包被安装,你的函数被绑定为一个脚本。 运行 my_script location/to/some/file.txt 从您的控制台到 运行 do_something_with_file with 'location/to/some/file.txt' in sys.argv[1].


使脚本编写更容易的流行第三方库是 click (quite old, but therefore super solid, and what I'd usually recommend) and typer(更现代,利用最近的内置 python 功能,如类型注释)。