编程语言
首页 > 编程语言> > python – 也可以作为命令行脚本运行的包的结构

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

作者:互联网

我用the ‘standard’ minimal structure写了一个包.它看起来像这样:

my_package/
    my_package/
        __init__.py
    setup.py

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

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

python my_package --arg1 "I like bananas."

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

python my_package/__init__.py --arg1 "I like bananas."

根据我的阅读,这是__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()

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

上面的工作,但PyCharm告诉我在__main__.py __init__是一个未解决的引用.对于该导入行上的MyClass也是如此.当我使用.__ init__而不是(带点)警告消失但是代码不再起作用,给我一个ImportError:尝试相对导入而没有已知的父包.

解决方法:

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

my_package/
    my_package/
        __init__.py
        cli_scripts.py
    setup.py

让我们假设您的__init__.py看起来像这样(作为旁注,我建议将那里定义的类移动到一个单独的文件中,然后只需在__init__中导入该文件):

class Test(object):

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

    def __call__(self):
        print(self.a)

现在包里面有一个额外的文件,利用你在包中实现的东西,我们称之为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()

我现在的建议是利用内部setup.py中的console_scripts entry point,现在看起来像这样:

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=[],
)

现在当你运行pip install.在顶级my_package文件夹中,将安装您的包. entry_points会自动为您生成一个可执行文件,您现在可以使用您在setup.py中给出的名称来调用,在此示例中为mypkg.这意味着您现在可以运行了

mypkg 5
这将调用demonst().

这条路:

>您不需要处理任何__main__文件
>您可以为脚本提供有意义的名称
>您不需要关心脚本是否可执行,或者指定使用python运行脚本
>您可以在列表entry_points中包含任意数量的这些内容
>它强制你编写你也可以从其他模块调用的函数,
而不是__main__

我觉得这很干净.
您可以在this blog中阅读有关entry_points的更多信息,它具有更多功能!
如果要使用__main__中指定的代码而不是此cli_scripts方法,可以查看this question.

标签:python,command-line,python-3-x,argparse,python-packaging
来源: https://codeday.me/bug/20190522/1152488.html