如何在列表推导或eval中使用多行语句?
我试图改变这段代码:
def f(x, y, b=''):
for i in x:
if i in y:
y.remove(i)
i *= 2
b += i
return b
进入像这样的lambda函数:
j=lambda x,y:''.join(eval('y.remove(i);i*2')if i in y else i for i in x)
在x
中,'onomatopoeia'
和y
之类的字符串是['o','a','o']
等列表。
但由于某种原因,它会返回语法错误。谁能解释一下呢?
答案 0 :(得分:3)
首先,由于循环中的副作用,你可能不应该用lambda重写它。无论如何你真的想要,不要使用评估。
我建议:
j = lambda x, y: ''.join((y.remove(i) or 2 * i) if i in y else i for i in x)
因为删除的结果是None
,所以or
的第二个参数将是结果。这避免了eval。但它比for-loop更糟糕。
正如对原始问题的评论中所述,2 * y.pop(y.index(i))
比or
构造更具可读性。您将在y
上循环两次,但性能似乎不是问题。
答案 1 :(得分:2)
我非常喜欢你的功能,但这会做你想要的。
from itertools import chain
j = lambda x, y: ''.join(filter(None,chain.from_iterable((i * 2,y.remove(i)) if i in y else i for i in x)))
print(j("'onomatopoeia'",['o','a','o']))
'oonoomaatopoeia'
答案 2 :(得分:0)
如果你想写出好的功能表达式(使用lambda
,map
,reduce
,filter
等),你应该避免副作用。
我强烈希望你的代码是一个函数,而不是一个有副作用的lambda。
这是一个lambda表达式中的无副作用实现:
>>> from functools import reduce
>>> (lambda x, y: reduce(lambda a, b: \
... (a[0]+2*b, a[1][:a[1].index(b)]+a[1][a[1].index(b)+1:]) if b in a[1] \
... else (a[0]+b, a[1]), x, ('',y))[0])('onomatopoeia', ['o','a','o'])
'oonoomaatopoeia'
我担心它不是短,也不是美丽,也不是易于理解 *因为人们希望它是一个lambda。 :/
(希望有人能提出改进建议)
仅仅是一个反例,在这种情况下不鼓励使用lambda。
恕我直言,python中lambdas的最大问题是没有像标准ML那样的where
语法来在同一个表达式中定义变量别名。所以,对于任何非常重要的事情,事情都会变得非常丑陋。
如果您有兴趣了解它的作用,那么我们的想法是使用reduce来运行自动机,其中结果(在每一步)都是计算的“状态”。
初始“状态”为('', ['o','a','o'])
,reduce函数将根据需要进行替换,从'onomatopoeia'
开始。
这是“国家”的演变:
( '', ['o','a','o'] ) 'o'
( 'oo', ['a','o'] ) 'n'
( 'oon', ['a','o'] ) 'o'
( 'oonoo', ['a'] ) 'm'
( 'oonoom', ['a'] ) 'a'
( 'oonoomaa', [] ) 't'
( 'oonoomaat', [] ) 'o'
( 'oonoomaato', [] ) 'p'
( 'oonoomaatop', [] ) 'o'
( 'oonoomaatopo', [] ) 'e'
( 'oonoomaatopoe', [] ) 'i'
( 'oonoomaatopoei', [] ) 'a'
( 'oonoomaatopoeia', [] )
我们只采用最后一个州的第一个元素。