Looking for idiomatic way to evaluate to False if argument is False in Python 3
我有一个函数链,所有函数都在类的其他地方定义:
1 | fus(roh(dah(inp))) |
其中
期望的结果是,如果
我试图使用三元运算符,但它们的计算不正确。
1 2 | def func(inp): return int(inp['value']) + 1 if inp else False |
号
如果
我知道我可以明确地做到:
1 2 3 4 5 | def func(inp): if inp == False: return False else: return inp['value'] + 1 |
但是有很多函数,这将使我的代码长度增加近四倍。它还一次又一次地重写完全相同的代码行,这对我来说意味着这是错误的做法。
我怀疑一个有争论的装饰师是答案,但我越是玩弄它,我就越不确定自己是怎么想的。
1 2 3 4 5 6 7 8 9 10 | def validate_inp(inp): def decorator(func): def wrapper(*args): return func(inp) if inp else False return wrapper return decorator @validate_inp(inp) def func(inp): return int(inp['value']) + 1 |
。
不幸的是,decorator调用引发了一个名称错误,未定义"inp"。但我不确定我是否使用了错误的装饰,或者装饰是错误的解决方案。
寻求评论、批评、建议和/或理智检查。
如果你发现这个试图解决你自己的问题…您可能希望使用空字典而不是布尔值false。道具到@chepner。
在我的应用程序中,使用false是"可以的",但没有提供任何优势,并且导致了一些代码块的厚重。
我发现用一本空字典来代替一切都比较简单。我将使用dict的函数与一个修饰符包装起来,该修饰符捕获通过引用
装饰师应该看起来像:
1 2 3 4 5 6 7 8 9 10 11 12 | def validate_inp(fun): def wrapper(inp): return fun(inp) if inp else False return wrapper @validate_inp def func(inp): return int(inp['value']) + 1 print(func(False)) print(func({'value': 1})) |
如果要将decorator与类成员一起使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 | def validate_inp(fun): def wrapper(self, inp): return fun(self, inp) if inp else False return wrapper class Foo(object): @validate_inp def func(self, inp): return int(inp['value']) + 1 if inp else False foo = Foo() print(foo.func(False)) print(foo.func({'value': 1})) |
号
I attempted to use ternary operators, but they don't evaluate correctly.
1
2 def func(inp):
return int(inp['value']) + 1 if inp else Falsethrows a TypeError, bool not subscriptable, if
i == False becauseinp['value'] is evaluated before the conditional.
号
这不是真的-代码有效。此外,你可以直接写
1 2 | def func(inp): return inp and (int(inp['value']) + 1) |
号
要自动包装这样的函数,请生成包装函数的函数:
1 2 3 4 | def fallthrough_on_false(function): def inner(inp): return inp and function(inp) return inner |
号
这应该通过使用
1 2 3 4 5 6 7 | from functools import wraps def fallthrough_on_false(function): @wraps(function) def inner(inp, *args, **kwargs): return inp and function(inp, *args, **kwargs) return inner |
号
除非您将一个值直接传递给decorator,否则不应将其参数化。在您的例子中,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> def validate_inp(f): ... def wrapper(inp): ... if not inp: ... return False ... return f(inp) ... return wrapper ... >>> @validate_inp ... def func(inp): ... return int(inp['value']) + 1 ... >>> func(False) False >>> func({'value': 1}) 2 |
。
这两条线
1 2 | @validate_inp def func(inp): |
可以这样理解
1 | func = validate_inp(func) |
。
因此,
如果要在一个类中实现同一个修饰器,只需考虑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> class Test(object): ... ... def validate_inp(fun): ... def wrapper(self, inp): ... if not inp: ... return False ... return fun(self, inp) ... return wrapper ... ... @validate_inp ... def func(self, inp): ... return int(inp['value']) + 1 ... ... >>> Test().func(False) False >>> Test().func({'value': 1}) 2 |
号
由于
这可能不是你想要的,但这些对你的事业有帮助吗?
1。用dictionary.get代替
1 2 3 4 5 | In [1548]: inp Out[1548]: {'6': 'Hi'} In [1549]: inp.get('5',99) Out[1549]: 99 |
1 2 | In [1550]: isinstance(inp, dict) Out[1550]: True |
。
把它们放在一起(inp和上面的字典一样)
1 2 | In [1554]: print"True" if isinstance(inp, dict) and len(inp.keys()) else"False" True |
另一个选择是:一个助手函数,它接受一个起始值和函数,并应用函数,只要它不遇到
1 2 3 4 5 6 7 8 | def apply(x, *functions): for func in functions: if x is False: return x # or break x = func(x) return x outp = apply(inp, dah, roh, fus) |
一个选项可能是定义一个自定义异常和一个小包装器:
1 2 3 4 5 6 7 | class FalseInput(Exception): pass def assert_not_false(inp): # I'll assume `inp` has to be precisely False, # and not something falsy like an empty dictionary. if inp is False: raise FalseInput return inp |
。
修改每个函数以引发相同的异常,而不是返回false。然后,只需在调用堆栈的顶部捕获一次异常,但首先包装输入。
1 2 3 4 | try: x = fus(roh(dah(assert_not_false(inp)))) except FalseInput: x = False |
。
这也可能更有效,因为您不必调用所有函数;如果