Python 2 list comprehension and eval

2019-06-16 15:57发布

How do you have a multiple line statement in either a list comprehension or eval?

I was trying to turn this code:

def f(x, y, b=''):
    for i in x:
        if i in y:
            y.remove(i)
            i *= 2
        b += i
    return b

Into a lambda function like so:

j=lambda x,y:''.join(eval('y.remove(i);i*2')if i in y else i for i in x)

In both x is a string such as 'onomatopoeia' and y is a list such as ['o','a','o'].

But for some reason, it returns a syntax error. Can anyone explain this?

3条回答
戒情不戒烟
2楼-- · 2019-06-16 16:46

First, you probably shouldn't rewrite this with a lambda because of the side-effects in the loop. If you really want to anyway, don't use an eval.

I'd suggest:

j = lambda x, y: ''.join((y.remove(i) or 2 * i) if i in y else i for i in x)

Because the result of remove is None the second argument to or will be the result. This avoids the eval. But it's still worse then a for-loop.


As noted in comments on the original question, 2 * y.pop(y.index(i)) is more readable than the or construct. You'll loop twice over y, but performance doesn't seem the issue.

查看更多
手持菜刀,她持情操
3楼-- · 2019-06-16 16:52

I would vastly prefer your function but this will do what you want.

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'
查看更多
We Are One
4楼-- · 2019-06-16 16:55

If you want to write good functional expressions (using lambdas, map, reduce, filter and so on), you should avoid side effects.

I would strongly prefer your code as a function rather than a lambda with side effects.

This is a sideeffect-free implementation in one lambda expression:

>>> 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'

I'm afraid it's not short nor beautiful nor easy to understand * as one would want it to be for a lambda. :/ (hopefully someone can suggest an improvement)

Just a counter-example to discourage the use of a lambda in this context.

IMHO the biggest problem with lambdas in python is that there is no where syntax like in Standard ML to define variable aliases in the same expression. So, things get ugly pretty quick for anything non trivial.


If you are interested in understanding what it does, the idea is to use reduce to run an automata, where the result (at each step) is the "state" of the computation.

The initial "state" is ('', ['o','a','o']), and the reduce function will do the replacement as needed, starting from 'onomatopoeia'.

This is the evolution of the "state":

( '',     ['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', [] )

and we take only first element of the last state.

查看更多
登录 后发表回答