我有一系列函数,都在类的其他地方定义:
fus(roh(dah(inp)))
其中inp
是字典,或bool(False)
。
期望的结果是,如果inp
或任何函数求值为False
,则函数堆栈将返回False
。
我尝试使用三元运算符,但它们没有正确评估。
def func(inp):
return int(inp['value']) + 1 if inp else False
抛出一个TypeError,bool不可订阅,如果i == False
因为inp['value']
在条件之前被评估。
我知道我可以明确地做到这一点:
def func(inp):
if inp == False:
return False
else:
return inp['value'] + 1
但是有很多功能,这几乎会使我的代码长度增加四倍。它也会一次又一次地重写完全相同的代码行,这对我来说这是错误的做事方式。
我怀疑有一个带有参数的装饰者就是答案,但是我玩的越多,我就越不确定。
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
不幸的是,装饰器调用抛出一个NameError,'inp'未定义。但我不确定我是否错误地使用了装饰器,或装饰器是错误的解决方案。
寻找评论,批评,建议和/或理智检查。
您可能希望使用空字典而不是布尔值False。道具到@chepner。
在我的应用程序中,使用False是“没问题”,但没有任何优势,并且导致了一些庞大的代码块。
我发现使用空字典更简单了。我正在使用装饰器包装使用dict的函数,该装饰器通过引用dict['value']
引用的dict
来捕获引发的KeyError,其中records.group_by { |h| h[:id] }.map { |id, arr|
{ id: id, note: arr.map { |h| h[:note] }.join } }
#=> [{:id=>"PU525", :note=>"FooBar"},
# {:id=>"DT525", :note=>"Hello World"},
# {:id=>"PU680", :note=>"Fubar"}]
为空。
答案 0 :(得分:9)
装饰者应该看起来像:
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}))
如果您想将装饰者与班级成员一起使用:
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}))
答案 1 :(得分:8)
我尝试使用三元运算符,但它们没有正确评估。
def func(inp): return int(inp['value']) + 1 if inp else False
抛出一个TypeError,bool不可订阅,如果
i == False
因为inp['value']
在条件之前被评估。
这不是真的 - 代码有效。此外,你可以写
def func(inp):
return inp and (int(inp['value']) + 1)
要自动包装这样的函数,请创建一个包装函数的函数:
def fallthrough_on_false(function):
def inner(inp):
return inp and function(inp)
return inner
这应该通过使用functools.wraps
来传递装饰器和名称来改进,并且它应该采用可变数量的参数来允许可选扩展:
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
答案 2 :(得分:4)
除非您将值直接传递给装饰器,否则不应对其进行参数化。在您的情况下,inp
实际上是传递给函数,而不是传递给装饰器。所以,实现就像这样
>>> 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
这两行
@validate_inp
def func(inp):
可以像这样理解
func = validate_inp(func)
因此,func
实际上是由wrapper
函数返回的validate_inp
函数。从现在开始,无论何时拨打func
,都会调用wrapper
,inp
只会传递给wrapper
。然后wrapper
将决定是否根据func
的值调用实际inp
。
如果要在类中实现相同的装饰器,则只需考虑self
函数中的第一个参数wrapper
。多数民众赞成。
>>> 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
由于wrapper
是实际func
,因此它也会接受self
和inp
。当您调用函数f
(实际为func
)时,您只需将self
作为第一个参数传递。
答案 3 :(得分:3)
这可能不是你想要的,但这些有助于你的事业吗?
1。
使用dictionary.get而不是[]
。您可以在此处定义回退值。例如。
In [1548]: inp
Out[1548]: {'6': 'Hi'}
In [1549]: inp.get('5',99)
Out[1549]: 99
isinstance
可用于检查变量是否为字典。
In [1550]: isinstance(inp, dict)
Out[1550]: True
将它们放在一起(inp与上面的字典相同)
In [1554]: print "True" if isinstance(inp, dict) and len(inp.keys()) else "False"
True
答案 4 :(得分:2)
一个选项可能是定义自定义异常和一个小包装器:
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。然后,只需在调用堆栈的顶部捕获异常一次,但首先包装输入。
try:
x = fus(roh(dah(assert_not_false(inp))))
except FalseInput:
x = False
这也可能更有效,因为您不一定需要调用所有函数;如果inp
以False
开头,assert_not_false
会立即引发异常,您将直接跳转到except
条款。
答案 5 :(得分:2)
另一种选择:一个辅助函数,它接受起始值和函数并应用函数,只要它不会遇到False
:
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)