包的结构,也可以作为命令行脚本运行

Bra*_*roy 5 python command-line argparse python-3.x python-packaging

我写了一个包含'标准'最小结构的包.它看起来像这样:

my_package/
    my_package/
        __init__.py
    setup.py
Run Code Online (Sandbox Code Playgroud)

__init__.py 包含一个类,因此可以像人们期望的那样简单地导入和使用.

但是,代码确实有助于以命令行方式使用,例如

python my_package --arg1 "I like bananas."
Run Code Online (Sandbox Code Playgroud)

起初,我刚刚进行了if __name__ == '__main__'检查,__init__然后使用argparse.这有效,但它不漂亮,因为它意味着你从命令行调用它,如下所示:

python my_package/__init__.py --arg1 "I like bananas."
Run Code Online (Sandbox Code Playgroud)

根据我的阅读,这是一个__main__.py文件进入的地方,它将作为文件夹内的默认脚本执行(类似于index.html网站上的文件).我的想法是然后简单地导入__init__.py,运行argparse并将参数提供给类构造函数.像这样:

import argparse
from __init__ import MyClass

parser = argparse.ArgumentParser()
parser.add_argument("--arg1", help="Some dummy value")

args = parser.parse_args()
my_class = MyClass(**vars(args))
my_class.do_stuff()
Run Code Online (Sandbox Code Playgroud)

这是类似的包应该如何构建,还是有更好的方法?


上面的工作, PyCharm告诉我,in __main__.py __init__是一个未解决的参考.同为MyClass对进口线.当我使用.__init__(带点)时,警告消失,但代码不再起作用,给我一个ImportError: attempted relative import with no known parent package.

Run*_*ith 5

我想向你建议一个不同的结构:

my_package/
    my_package/
        __init__.py
        cli_scripts.py
    setup.py
Run Code Online (Sandbox Code Playgroud)

让我们假设您的__init__.py外观是这样的(作为旁注,我建议将其中定义的类移动到一个单独的文件中,然后简单地将该文件导入到 中__init__):

class Test(object):

    def __init__(self, a)
        self.a = a

    def __call__(self):
        print(self.a)
Run Code Online (Sandbox Code Playgroud)

现在包中有一个额外的文件,它利用了你在包中实现的东西,我们称之为cli_scripts.py

import argparse

from my_package import Test


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("a", type=int, help="Just an example argument")
    return parser.parse_args()

def demonstration():
    args = parse_args()
    t = Test(a=args.a)
    t()
Run Code Online (Sandbox Code Playgroud)

我现在的建议是利用里面的console_scripts 入口点setup.py,现在看起来像这样:

from setuptools import setup

setup(
    name='testpy',
    version='0.1',
    description='Just an example',
    author='RunOrVeith',
    author_email='xyz@mailinator.com',
    packages=["my_package"],
    entry_points={
        "console_scripts": ["mypkg=my_package.cli_scripts:demonstration"]},
    install_requires=[],
)
Run Code Online (Sandbox Code Playgroud)

现在,当您pip install .在顶级my_package文件夹中运行时,您的软件包将被安装。该entry_points自动生成一个可执行文件给你,你现在可以用你给它里面的名setup.py,在这个例子中mypkg。这意味着您现在可以运行

mypkg 5 这将调用demonstration().

这边走:

  • 你不需要处理任何__main__文件
  • 你可以给你的脚本一个有意义的名字
  • 你不需要关心你的脚本是否可执行,或者指定运行脚本 python
  • 您可以在列表中包含任意数量的这些 entry_points
  • 它迫使您编写也可以从其他模块调用的函数,而不是 __main__

我觉得这很干净。您可以entry_points此博客中阅读更多信息,它具有更多功能!如果你想使用指定的代码__main__而不是这种cli_scripts方法,你可以看看这个问题