在 Python 中更清晰地表示规则 (if-else)

Cleaner way to represent Rules (if-else) in Python

我正在尝试寻找一种设计模式(或 maybe an algorithm)来帮助我以更清晰的方式编写这些规则。有什么建议吗?

def get_rules(user, value):
    if 500 <= value < 5000 and not user.address:
        return [REQUEST_ADDRESS]

    if value >= 5000:
        if not user.address and not user.phone:
            return [REQUEST_ADDRESS, REQUEST_PHONE]
        if user.address and not user.phone:
            return [REQUEST_PHONE]
        if not user.address and user.phone:
            return [REQUEST_ADDRESS]

    # Potentially ~20 more conditions here based on various attributes of user
    return [STATES.REQUEST_NONE]

注意:我不是在寻找规则引擎,因为我不想通过在 python 中添加 "business friendly" DSL 来使我的代码复杂化。 Python 本身就是一种简单的语言来编写这些规则。

有趣的阅读:http://martinfowler.com/bliki/RulesEngine.html(但我仍在努力远离 "framework" 为我做这件事)。

在这种情况下你可以使用字典:

resdict = {(False, False): [REQUEST_ADDRESS, REQUEST_PHONE],
           (True, False): [REQUEST_PHONE],
           (False, True): [REQUEST_ADDRESS]}
return resdict[(user.address, user.phone)]

您还可以使用列表理解:

return [req for req, haveit in zip([REQUEST_ADDRESS, REQUEST_PHONE], [user.address, user.phone]) if not haveit]

或更简单的列表追加:

res = []
if not user.address:
    res.append(REQUEST_ADDRESS)
if not user.phone:
    res.append(REQUEST_PHONE)

您正在使用 "if a and not b else check not a and b else check not a and not b" 策略检查许多不同的组合,以确定您需要发送哪些请求组合。

相反,只检查您遗漏的内容:

missing = []
if not user.phone:
    missing.append(REQUEST_PHONE)
if not user.address:
    missing.append(REQUEST_ADDRESS)

return missing or [REQUEST_NONE]

如果我没理解错的话,你就有了用户的属性列表。如果一个为假,则应将 REQUEST 值添加到列表中。那么这可能会有所帮助:

# define all your combinations here:
mapping = {'address': REQUEST_ADDRESS, 'phone': REQUEST_PHONE, …)

return [value for key, value in mapping.items()
        if not getattr(user, key, None)]

看起来您的 "rules" 可以归结为:为对象 user 中不作为属性存在的字段请求值。我假设属性到请求的映射可以是任意的;您可以将其表示为字典映射,例如像这样:

rulemap = { 
      "address": REQUEST_ADDRESS, 
      "phone": REQUEST_PHONE, 
      # etc.
    }

然后,您可以通过检查 rulemap 中的哪些键未作为对象 user:

中的属性来获取要发出的请求列表
return [ rulemap[fld] for fld in rulemap.keys() if fld not in user.__dict__ ]