【问题标题】:How to output list of legal argument when input is illegal?输入非法时如何输出合法参数列表?
【发布时间】:2018-02-28 21:11:58
【问题描述】:

我需要实现很多这样的案例选择功能:

def foo1(bar1):
    if bar1 == 'A':
        do something
    elif bar1 == 'B':
        do something
    elif ...
    ...
    else:
        raise ValueError('legal input of bar1 should be {}'.format(list_of_bar))

def foo2(bar2):
    if bar2 == 'A':
        do something
    elif bar2 == 'B':
        do something
    elif ...
    ...
    else:
        raise ValueError('legal input of bar2 should be {}'.format(list_of_bar))

'''

根据“不要自己重复”,有没有办法避免重复引发错误的最后一步并打印正确参数的列表?我认为装饰师可能会这样做,但不知道如何制作。提前致谢。

更新

我自己用检查模块实现了它。但我还是希望能得到一些建议或更好的解决方案

import inspect
from functools import wraps
import re

def test_none(func):
    _code = inspect.getsource(func)
    _list = re.findall(r'if (\w+) == (\w+)', _code)
    assert all(_list[0][0] == name for name, case in _list)
    _arg = _list[0][0]
    _case = tuple(case for name, case in _list)

    @wraps(func)
    def wrapper(*args, **kwargs):
        results = func(*args, **kwargs)
        if results is None:
            raise ValueError(
                    'Legal value of \'{arg}\' should be anyone of {case}'.format(
                    arg=_arg, case=_case))
        return results
    return wrapper

@test_none
def foo(bar):
    if bar == 0:
        return 1
    elif bar == 1:
        return 2

测试示例:

foo(3)
ValueError: Legal value of 'bar' should be anyone of ('0', '1')

【问题讨论】:

  • 您正在寻找将"A" 映射到do something"B"do something else 等的东西。换句话说,您想要一个字典。
  • 但是有了字典,我还需要做最后的 raise Error 和打印步骤,这是我真的想通过装饰器或其他“黑魔法”来避免。

标签: python metaprogramming decorator


【解决方案1】:

我通常发现用字典更清楚地表达了“多例”模式。

我在这里假设对于每种情况,我们都有一个不同的函数要调用,但是如果每个值只是您要返回的整数或任何其他对象,则该模式有效。

例如CASES 字典清楚而紧凑地向代码读者发出不同情况的信号。

CASES = {
    'A': do_something,
    'B': do_something_else,
    ...
}

def foo(bar):
    if bar not in CASES:
        raise ValueError('legal input of bar should be {}'.format(list_of_bar))

    # do stuff
    CASES[bar]()

另一种方法是使用“请求宽恕,而不是许可”模式。我发现在这种特殊情况下,它不像上面那样清楚。

def foo(bar):
    try:
        func = CASES[bar]
    except KeyError:
        raise ValueError(...)
    # do stuff
    func()

或使用字典 .get 方法作为另一种方式,但我认为对于这种特定情况,它不像第一种方式那样清楚。

def foo(bar):
    func = CASES.get(bar)
    if func is None:
         raise ValueError(...)
    # do stuff
    func()

【讨论】:

  • 我喜欢所有这些响应 - 并且认为每个范例都有很好的用例。干得好!
  • 感谢您的回答。但是如果我有很多类似的函数 foo 要定义,那么整体结构也会有很多冗余。我想知道是否有一种方法可以在没有引发错误步骤的情况下使用函数“foo”,然后在最后一步吐出一个新函数。
【解决方案2】:

使用字典将可能的输入映射到操作,如下所示:

def foo(bar):
    def a():
        print('a():')

    def b():
        print('b():')

    def c():
        print('c():')

    actions = {'A': a, 'B': b, 'C': c}
    if bar in actions:
        actions[bar]()
    else:
        raise ValueError('legal input of bar should be {}'.format(sorted(actions.keys())))

演示:

>>> foo('A')
a():
>>> foo('Z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "x.py", line 15, in foo
    raise ValueError('legal input of bar should be {}'.format(sorted(actions.keys())))
ValueError: legal input of bar should be ['A', 'B', 'C']

【讨论】:

  • Yes 字典在这种情况下工作得很好。对不起,如果我没有表达清楚,但我需要的是避免最后的“raise ValueError”步骤。因为我需要一堆具有这种相似结构的不同功能,所以我在想有没有办法绕过重复的引发错误和打印步骤。我认为这可能需要一些元编程。
猜你喜欢
  • 1970-01-01
  • 2014-08-24
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 2020-12-05
相关资源
最近更新 更多