【问题标题】:Short circuit list of functions python函数python的短路列表
【发布时间】:2021-07-09 22:43:37
【问题描述】:

我有一个类有这样的方法

class Validator:
    def _is_valid_code(self):
        return bool(#some logic here)

    def _is_valid_role(self):
        return bool(#some logic here)

    def _is_valid_age(self):
        return bool(#some logic here)
    .
    .
    .

如果都是 True 我想继续,否则返回一个字符串

if not _is_valid_code():
    #short circuit and return a string
    return "not valid code"
if not _is_valid_role():
    #short circuit and return a string
    return "not valid role"
if not _is_valid_age():
    #short circuit and return a string with description
    return "not valid age"
#if we got here the request is valid so return a valid response
return valid_scenario

现在我对此没有任何问题,因为只有三个条件,但是例如,如果我有更多,比如说 10 个条件,我最终会遇到很多 if 场景,所以我在想如果这样的事情是可能的,我只是将条件逻辑和条件添加到列表中,仅此而已,问题是如果条件为假,则获取字符串值

conditions = [_is_valid_code(), _is_valid_role(), _is_valid_age()]
if all_conditions_true(conditions):
    return valid_scenario
else:
    return last_message_before_shortcut

还想知道这是否有效,是否可以被视为 Python 并推荐

【问题讨论】:

  • 创建方法/错误字符串对列表。然后遍历该列表,调用该方法,如果失败,则返回字符串。将其设为类变量,这样实际上可以为您节省大量时间
  • 如果发生错误,我不会返回字符串。让每个函数要么返回有效场景,要么引发异常。这样一来,如果你完全返回,你就知道你有有效的场景。
  • 我忘了提到在所有场景中返回类型都是 json,实际上我在应用时返回了一个 http 代码和描述,有效的场景与无效的不同,因为是没有消息的 204,字符串只是为了说明我想做的事情,但我有几个 403,只有消息不同

标签: python python-3.x


【解决方案1】:

您可以使用 dict 来存储映射到其各自字符串的函数。

checks = {
    _is_valid_code: "not valid code",
    _is_valid_role: "not valid role",
    _is_valid_age: "not valid age",
    }

for f in checks:
    if not f():
        return checks[f]
return valid_scenario

请注意,字典在 Python 3.7+ 中保留了插入顺序。如果您使用的是旧版本或想要更严格的排序,请使用 OrderedDict 或包含函数和字符串的元组列表。


这本身就是完美的 Pythonic,但我不知道上下文,所以我不能确定你的情况。例如,如果valid_scenario 不是字符串,我强烈建议使用异常而不是混合返回类型。这个问题涵盖了:Why should functions always return the same type? 如果函数正在检查 error 条件,我建议使用相同的方法。

【讨论】:

  • 这很好,但我会将其设为元组列表而不是字典。您在这里没有使用任何特定于 dict 的行为。
  • @Kirk 我在checks[f] 中使用查找。但是是的,它不需要那样,这只是我的想法:如果函数失败,那么你才需要获取关联的字符串。您也可以在元组列表中执行 for f, s in checks.items() 或等效项。
  • 这应该只是一对列表,但正确的一般方法
【解决方案2】:

我会这样做:

def one():
    """string from one"""
    return False 

def two():
    """string from two"""
    return False 

def three():
    """string from three"""
    return True

def four():
    """string from four"""
    return False

conditions=[one, two, three, four]

然后使用next 找到第一个TrueFalse 以从函数中读取关联的文档字符串:

>>> print( next(f.__doc__ for f in conditions if f()) )  
string from three  

您可以使用next 的默认值来表示所有内容都是相同的(视情况而定):

next((f.__doc__ for f in conditions if f()), "All False")

或者,正如你所说的那样:

def validator(conditions):
    return next((f.__doc__ for f in conditions if f()), None)

优点:

  1. 如果在类中使用这种方法,字符串会自动在类范围内(不是每次都重新创建);

  2. [(one,"string from one"),(two,"string from two"),...]更容易编辑(对我来说);

  3. 字符串和相关的测试代码就在函数中;

  4. 带有条件的next 提供短路并在第一个目标布尔值处停止;

  5. 条件列表[one,two,three,...][(one,"string from one"),(two,"string from two"),...] 更容易让我看到和理解

  6. 还有一件事!您可以完全跳过 __doc__ 字符串,只需使用描述性函数名称:

    next((f.__name__ for f in conditions if f()), default)

  7. 如果你想这样做老派,你也可以使用nextfunc_name:"associated string" 的字典。

【讨论】:

  • 这是聪明一半的方法。只需使用方法元组的列表,msg
  • 就我个人而言,我发现使用__doc__ 字符串与元组列表更容易维护一个函数,因为每个测试结果和要测试的代码都在同一个地方。为我工作!
  • 我也使用__doc__ 来处理这些事情。我写的答案与 OP 的习惯最相似(也就是说,不要一次更改 太多 )。在我自己的项目中,我绝对会有if not function(): return function.__doc__
【解决方案3】:

我写过这样的东西:

for condition_is_ok, error_msg in [
    (_is_valid_code, "not valid code"),
    (_is_valid_role, "not valid role"),
    (_is_valid_age, "not valid age"),
]:
    if not condition_is_ok():
        return error_msg

或者,更改验证器的工作方式:

  • 如果失败,返回一个解释原因的字符串。
  • 如果通过,则返回 None。
class Validator:
    def _code_error(self):
        if ...:
            return "not valid code"
        return None

for checker in [_code_error, ...]:
    result = checker
    if result is not None:
        return result

【讨论】:

  • 这是正确的方法但不要每次都重新创建列表。应该是类变量
  • 绝对!或者,如果您可以建立命名模式,您可以使用 for function in dir(cls): if function.startswith('_validate_'): ... 之类的东西在运行时检查类以收集所有定义的验证函数。为什么要重复自己?让 Python 帮你偷懒。
猜你喜欢
  • 2019-04-04
  • 1970-01-01
  • 2014-05-30
  • 2011-03-25
  • 2019-09-27
  • 1970-01-01
  • 1970-01-01
  • 2013-05-31
  • 2011-04-12
相关资源
最近更新 更多