Python 在一行中使用表达式两次-作为条件和字符串格式?

Python 在一行中使用表达式两次-作为条件和字符串格式?,python,lambda,formatting,conditional,Python,Lambda,Formatting,Conditional,我发现在很多不同的项目中,我编写了很多代码,需要计算一个(相当复杂,计算起来可能很昂贵)表达式,然后对它进行处理(例如,将其用于字符串格式),但前提是表达式为真/非无 例如,在许多地方,我最终做了如下工作: result += '%s '%( <complexExpressionForGettingX> ) if <complexExpressionForGettingX> else '' 但无需重新键入表达式(或重新计算表达式,以防代价高昂的函数调用) 显然,可以通过

我发现在很多不同的项目中,我编写了很多代码,需要计算一个(相当复杂,计算起来可能很昂贵)表达式,然后对它进行处理(例如,将其用于字符串格式),但前提是表达式为真/非无

例如,在许多地方,我最终做了如下工作:

result += '%s '%( <complexExpressionForGettingX> ) if <complexExpressionForGettingX> else ''
但无需重新键入表达式(或重新计算表达式,以防代价高昂的函数调用)

显然,可以通过各种冗长的方式(例如,将表达式拆分为多个语句并将表达式分配给一个临时变量)轻松实现所需的逻辑,但这有点麻烦,因为这似乎是一个相当普遍的问题,而且python非常酷(特别是对于函数性的东西)我想知道是否有一个好的,优雅的,简洁的方法来做到这一点

我目前最好的选择是定义一个短期lambda来处理它(比多个语句好,但有点难读):


。。。但是,由于我在许多不同的代码库中执行此操作,我宁愿使用内置的库函数或一些巧妙的python语法(如果存在这样的东西)

python没有表达式作用域(),大概是因为语法的滥用和混乱超过了它的优点

如果您必须使用表达式作用域,最坏的选择是滥用生成器:

result += next('%s '%(e) if e else '' for e in (<complexExpressionForGettingX>,))
result+=next(“%s%”(e)if e else“”,用于(,)中的e)

我绝对喜欢一行。但有时它们是错误的解决方案

在专业软件开发中,如果团队规模大于2,那么您花在理解别人编写的代码上的时间要多于写新代码上的时间。这里给出的一行肯定会让人困惑,所以只需写两行(即使你在文章中提到了多个语句):

X=
结果+='%s'%X如果X其他''

这是清晰、简洁的,每个人都能立即理解这里发生的事情。

您可以定义一次条件格式函数,然后重复使用它:

def cond_format(expr, form, alt):
    if expr:
        return form % expr
    else:
        return alt
用法:

result += cond_format(<costly_expression>, '%s ', '')
result+=cond_格式(,'%s','')

您可能希望重复执行此操作以构建字符串。在更全局的视图中,您可能会发现
filter
(或
itertools.ifilter
)执行您希望的值集合操作

你会得到这样的结果:

' '.join(map(str, filter(None, <iterable of <complexExpressionForGettingX>>)))

根据您计算值的方式,可能是等效列表或生成器更具可读性

听了回答(谢谢大家!)我现在确信,如果不定义新函数(或lambda函数),就无法在Python中实现我想要的功能,因为这是引入新范围的唯一方法

为了清楚起见,我决定将其作为一个可重用函数(而不是lambda)来实现,因此为了其他人的利益,我想我应该共享我最终提出的函数——它足够灵活,可以处理多个额外的格式字符串参数(除了用于决定是否进行格式化的主参数之外);它还附带pythondoc以显示正确性和说明用法(如果您不确定**kwargs是如何工作的,请忽略它,这只是一个实现细节,是我在格式字符串参数变量列表之后实现可选defaultValue=kwarg的唯一方法)


result+='%s'(或“”)怎么样
?@wim-返回
'
用于否定表达式。OP想要
'
啊,你说得对,呜呜。+1。虽然我认为它比OP提供的lambda内容更复杂,但在更复杂的情况下,它是一个值得考虑的有效且不错的替代方案。-1:这比为中间结果想出一个名称要好lt?这既令人困惑又令人费解,而且要求你无论如何都要想出一个名称。只需将它分成两条语句。@Nedbatcheld添加一条语句并不总是有意义的,例如,如果作用域表达式本身嵌入了一个条件中。当然,在这种情况下,重构可能是一个好主意。尽管我不相信使用of comprehensions与我最初的lambda表达式一样清晰,+1用于重要和有用的观察,即python没有表达式级别的作用域(只有类和函数定义作用域,加上lambdas/comprehensions之类的东西,这在幕后是一种函数)。这就解释了为什么在Python中,除了定义函数(或lambda函数)之外,没有其他方法可以做我想要做的事情。-1:hmmm是的,有时它们是错误的,但有时(特别是当您需要在函数中多次执行时)在一个表达式中进行操作要比在名称空间中引入一个虚假的短期变量(例如X)并占用源文件的两行来执行一个操作(甚至对于“专业软件开发”的imho)清楚得多-我认为在我的情况下,这种方法会妨碍可读性,特别是与定义帮助函数来处理这种常见情况相比。我在问题中明确表示,我考虑过这种方法。也许一个有意义的变量名会改进这种策略。在这种情况下,额外的一行几乎是一个注释。是的,你定义了它非常正确!我选择X只是因为选择了OP,并且因为缺少X可能是什么样的上下文。有时我甚至为一个数字定义变量,比如
1
,只是为了文档的原因,例如,
correction\u for_offset=1
。这使代码更容易理解和维护。是的,我给你+1来编写它我已经在我的问题中提出了这种可能的方法。我还添加了一个更完整、功能更全面的condFormat方法作为我对问题的回答
X = <complexExpressionForGettingX>
result += '%s '% X  if X else ''
def cond_format(expr, form, alt):
    if expr:
        return form % expr
    else:
        return alt
result += cond_format(<costly_expression>, '%s ', '')
' '.join(map(str, filter(None, <iterable of <complexExpressionForGettingX>>)))
>>> ' '.join(map(str, filter(None, range(-3, 3))))
'-3 -2 -1 1 2'
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)