使用 argparse 处理 if-else 的最佳方法?

Best way to handle if-else with argparse?

假设我们有很多参数解析选项

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Download files from Canvas.')

    parser.add_argument(
        '-user_id',
        type=str,
        default="",
    )

    parser.add_argument(
        '-course_id',
        type=str,
        default="",
    )

    parser.add_argument(
        '-student_id',
        type=str,
        default="",
    )
# ...
    parser.add_argument(
        '-book_id',
        type=str,
        default="",
    )

我想运行函数由输入

决定
if user_id != "" and course_id == "" and student_id != "" and book_id == "":
    f()

elif user_id != "" and course_id == "" and student_id != "" and book_id != "":
    g()

# ...

elif user_id == "" and course_id == "" and student_id == "" and book_id == "":
    h()

等等。嗯,这些是很多 if-else 语句。我想消除必须做所有这些。有没有人有足够的方法来减少函数 运行 之前变量之间的比较量?还是取决于上下文?谢谢!!

构建一个将选项组合映射到处理程序函数的字典。

当你这样写的时候:

if user_id != "" and course_id == "" and student_id != "" and book_id == "":

您实际上是将这四个选项视为布尔元组 值。你在问,“参数是否等于(假,真, 假,真)?”

我们可以利用这一点。首先,我们需要代码来翻译 选项到一个实际的元组中。类似于:

args = parser.parse_args()
sig = tuple(getattr(args, x) == '' for x in ('user_id', 'course_id', 'student_id', 'book_id'))

如果您的程序没有接收到命令行参数,这会设置 sig 等于 (True, True, True, True)。如果你通过了--student-id 1, 这变成 (True, True, False, True).

我们可以创建一个将这些模式映射到处理程序的字典 功能:

argmap = {
    (False, True, False, True): f,
    (False, True, False, False): g,
    (True, True, True, True): h,
}

有了这两种机制,我们就可以查找处理程序 给定一组这样的参数:

handler = argmap.get(sig)
if handler is None:
    print('no handler for', args)
else:
    handler()

将它们放在一起,我们得到:

import argparse


def f():
    print('this is function f')


def g():
    print('this is function g')


def h():
    print('this is function h')


argmap = {
    (False, True, False, True): f,
    (False, True, False, False): g,
    (True, True, True, True): h,
}


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Download files from Canvas.')

    parser.add_argument(
        '--user-id',
        default='',
    )

    parser.add_argument(
        '--course-id',
        default='',
    )

    parser.add_argument(
        '--student-id',
        default='',
    )

    parser.add_argument(
        '--book-id',
        default='',
    )

    args = parser.parse_args()
    sig = tuple(getattr(args, x) == '' for x in ('user_id', 'course_id', 'student_id', 'book_id'))
    handler = argmap.get(sig)
    if handler is None:
        print('no handler for', args)
    else:
        handler()

这产生了输出:

$ python argtest.py
this is function h
$ python argtest.py --user-id 1 --student-id 1
this is function f
$ python argtest.py --user-id 1 --student-id 1 --book-id 1
this is function g
$ python argtest.py --user-id 1
no handler for Namespace(user_id='1', course_id='', student_id='', book_id='')