首页 > 解决方案 > 使用python函数或方法制作命令行实用程序的最佳方法?

问题描述

我写了很多小实用程序函数,我想直接通过命令行使用它们,也可以作为 python 函数导入以供其他实用程序使用。目前我所做的是将我的函数写在一个文件中,并在同一个文件中if __name__ == "__main__":使用 argparse 与命令行上的函数进行交互。例如,假设我有文件math.py

import argparse

def add_or_subtract(a: float, b: float, c: float = 1., add: bool = True) -> float:
    """
    Do some random math

    Parameters
    ----------
    a : float
        A number
    b : float
        Another number
    c : float, optional
        Another number
    add : bool, optional
        Whether to add or subtract c

    Returns
    -------
    answer : float
        The answer
    """
    if add:
        return a+b+c
    else:
        return a+b-c

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("a", type=float, help="a number")
    parser.add_argument("b", type=float, help="another number")
    parser.add_argument("-c", "--c", type=float, help="another number", default=1.)
    parser.add_argument("-a", "--add", action=store_true)
    parser.parse_args()
    print(add_or_subtract(parser.a, parser.b, parser.c, parser.add))

基本上我觉得我做了很多重复的定义论点、它们可接受的类型和它们的解释。如果我更改函数的一些参数,我必须记住在三个地方更新它。我想知道是否有更简单的方法。

我一直在inspect尝试根据函数中的参数添加 CLI 参数,但我想要一些“更聪明”的东西,它知道强制参数和可选参数、可接受的类型、布尔标志等之间的区别。甚至如果还可以解析文档字符串以获得帮助,则更好。理想的场景是一种“命令行化”函数的装饰器。

像我描述的那样存在吗?或者有没有更好的方法来做我想做的事。

标签: pythonargparse

解决方案


您为什么不尝试将命令实现为类,然后再继承它们呢?

像这样的东西可能会起作用:

class CommandArgument:

    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs

    def add_to_parser(self, parser: argparse.ArgumentParser):
        parser.add_argument(*self.args, **self.kwargs)


class BaseAddOrSubCommand:

    a = CommandArgument('a', type=float, help='a number')
    b = CommandArgument('b', type=float, help='another number')
    c = CommandArgument('b', type=float, help='another number')
    args = [a, b, c]

    def __init__(self):
        self.parser = argparse.ArgumentParser
        for arg in self.args:
            arg.add_to_parser(self.parser)
        self.parser.parse_args()

    def execute(self):
        if self.parser.add:
            return self.parser.a + self.parser.b + self.parser.c
        else:
            return self.parser.a + self.parser.b - self.parser.c


class MultiplySumOrSubCommand(BaseAddOrSubCommand):

    mult = CommandArgument('mult', type=float, help='multiply result with me')
    args = BaseAddOrSubCommand.args + [mult]

    def execute(self):
        return super().execute() * self.parser.mult


if __name__ == '__main__':
    command = MultiplySumOrSubCommand()
    print(command.execute())

推荐阅读