Python 2列表理解和评估

时间:2015-06-22 17:29:24

标签: python lambda eval list-comprehension

如何在列表推导或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']等列表。

但由于某种原因,它会返回语法错误。谁能解释一下呢?

3 个答案:

答案 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)

如果你想写出好的功能表达式(使用lambdamapreducefilter等),你应该避免副作用。

我强烈希望你的代码是一个函数,而不是一个有副作用的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', [] )

我们只采用最后一个州的第一个元素。