我发现在许多不同的项目中,我正在编写大量代码,我需要在其中评估(中等复杂,可能代价高昂的评估)表达式,然后对其执行某些操作(例如,将其用于字符串格式化),但仅当表达式为True / non-None时。
例如,在很多地方,我最终会做如下的事情:
result += '%s '%( <complexExpressionForGettingX> ) if <complexExpressionForGettingX> else ''
...我想这基本上是一个特殊情况,想要返回一个表达式的某个函数,但只有当该表达式为True时,即:。
f( e() ) if e() else somedefault
但不重新输入表达式(或重新评估它,以防它是一个代价高昂的函数调用)。
显然,所需的逻辑可以通过各种冗长的方式轻松实现(例如,通过将表达式拆分为多个语句并将表达式分配给临时变量),但这有点蹩脚,因为这看起来非常通用问题,因为python非常酷(特别是对于功能性的东西)我想知道是否有一个漂亮,优雅,简洁的方法来做它?
我目前最好的选择是定义一个短命的lambda来处理它(比多个语句更好,但有点难以阅读):
(lambda e: '%s ' % e if e else '')( <complexExpressionForGettingX> )
或编写我自己的实用程序功能,如:
def conditional(expr, formatStringIfTrue, default='')
...但是由于我在许多不同的代码库中执行此操作,所以我更倾向于使用内置库函数或一些聪明的python语法(如果存在这样的话)
答案 0 :(得分:7)
我绝对喜欢单行。但有时它们是错误的解决方案。
在专业软件开发中,如果团队规模是> 2,你花了更多的时间来理解别人写的代码,而不是编写新的代码。这里介绍的单行是绝对令人困惑的,所以只做两行(即使你在帖子中提到了多个语句):
X = <complexExpressionForGettingX>
result += '%s '% X if X else ''
这清楚,简洁,每个人都立即明白这里发生了什么。
答案 1 :(得分:4)
Python没有表达式范围(Is there a Python equivalent of the Haskell 'let'),大概是因为语法的滥用和混淆超过了优点。
如果你绝对必须使用表达式范围,那么最差的选择就是滥用生成器理解:
result += next('%s '%(e) if e else '' for e in (<complexExpressionForGettingX>,))
答案 2 :(得分:3)
您可以定义一次条件格式化函数,并重复使用它:
def cond_format(expr, form, alt):
if expr:
return form % expr
else:
return alt
用法:
result += cond_format(<costly_expression>, '%s ', '')
答案 3 :(得分:1)
听到回复后(感谢大家!)我现在确信在没有定义新函数(或lambda函数)的情况下,没有办法在Python中实现我想要的东西,因为这是引入新范围的唯一方法。
为了最好的清晰度,我认为这需要实现为可重用的功能(而不是lambda),所以为了别人的利益,我想我会分享我最终想出的功能 - 这足够灵活,可以应对多个附加格式字符串参数(除了用于决定是否要进行格式化的主参数);它还附带pythondoc以显示正确性并说明用法(如果你不确定** kwargs的工作方式如何忽略它,它只是一个实现细节,是我能看到实现一个可选的defaultValue = kwarg的唯一方法格式字符串参数的变量列表)。
def condFormat(formatIfTrue, expr, *otherFormatArgs, **kwargs):
""" Helper for creating returning the result of string.format() on a
specified expression if the expressions's bool(expr) is True
(i.e. it's not None, an empty list or an empty string or the number zero),
or return a default string (typically '') if not.
For more complicated cases where the operation on expr is more complicated
than a format string, or where a different condition is required, use:
(lambda e=myexpr: '' if not e else '%s ' % e)
formatIfTrue -- a format string suitable for use with string.format(), e.g.
"{}, {}" or "{1}, {0:d}".
expr -- the expression to evaluate. May be of any type.
defaultValue -- set this keyword arg to override
>>> 'x' + condFormat(', {}.', 'foobar')
'x, foobar.'
>>> 'x' + condFormat(', {}.', [])
'x'
>>> condFormat('{}; {}', 123, 456, defaultValue=None)
'123; 456'
>>> condFormat('{0:,d}; {2:d}; {1:d}', 12345, 678, 9, defaultValue=None)
'12,345; 9; 678'
>>> condFormat('{}; {}; {}', 0, 678, 9, defaultValue=None) == None
True
"""
defaultValue = kwargs.pop('defaultValue','')
assert not kwargs, 'unexpected kwargs: %s'%kwargs
if not bool(expr): return defaultValue
if otherFormatArgs:
return formatIfTrue.format( *((expr,)+otherFormatArgs) )
else:
return formatIfTrue.format(expr)
答案 4 :(得分:0)
据推测,您希望重复 来构建字符串。使用更全局的视图,您可能会发现filter
(或itertools.ifilter
)执行您想要的值集合。
你会结束这样的事情:
' '.join(map(str, filter(None, <iterable of <complexExpressionForGettingX>>)))
使用None
作为filter
的第一个参数表示接受任何真值。作为一个简单表达式的具体例子:
>>> ' '.join(map(str, filter(None, range(-3, 3))))
'-3 -2 -1 1 2'
根据您计算值的方式,可能是等效列表或生成器理解更具可读性。