【问题标题】:Python 2 list comprehension and evalPython 2 列表理解和评估
【发布时间】:2015-06-22 17:29:23
【问题描述】:

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

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

【问题讨论】:

  • xy 的值是什么?
  • 你到底为什么要这样做?
  • 预期输出是什么?? oonoomaatopoeia ?
  • 也许他正在寻找一种使用 lambda 的漂亮方法
  • 我同意其他人的观点,即你永远不应该这样做,但如果你这样做,至少不要使用 eval。您可以简单地使用 y.pop(y.index(i)) + i2 * y.pop(y.index(i)) 代替您的 eval 调用。附带说明一下,我怀疑您对性能感兴趣,但是当您一一删除列表中的所有元素时,该算法的效率相当低;更快的替代方法是使用 collections.Counter 并减少字母的数量。

标签: python lambda eval list-comprehension


【解决方案1】:

首先,由于循环中的副作用,您可能不应该用 lambda 重写它。如果您真的想这样做,请不要使用 eval。

我建议:

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

因为remove的结果是None,所以or的第二个参数就是结果。这避免了评估。但它仍然比 for 循环更糟糕。


正如 cmets 在原始问题中所述,2 * y.pop(y.index(i))or 结构更具可读性。您将在 y 上循环两次,但性能似乎不是问题。

【讨论】:

    【解决方案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'
    

    【讨论】:

    • 为什么不简单地''.join(2 * y.pop(y.index(i)) if i in y else i for i in x)
    • @l4mpi,因为我使用的是 OP 自己的代码,所以索引也有成本,所以并不比过滤更好。如果由我决定,我不会使用任何一种方法
    • 我同意两者都不是真正可行的方法,但 pop 变体在 IMO 上更具可读性。我怀疑速度是一个问题,如果它完全消除remove 调用可能是最好的行动方案(例如使用Counter 并减少字母计数)。
    • @l4mpi,正如我所说,我正在使用 OP 提供的代码并让它按照提供的方式工作,而不是提供我个人使用的方式。 ''.join(2 * y.pop(y.index(i)) if i in y else i for i in x) 也不是我会使用的东西
    【解决方案3】:

    如果你想写出好的函数式表达式(使用lambdas、mapreducefilter等等),你应该避免副作用。

    我强烈希望您的代码作为函数而不是具有副作用的 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 中 lambda 的最大问题是没有像标准 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', [] )
    

    我们只取最后一个状态的第一个元素。

    【讨论】:

      猜你喜欢
      • 2015-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      相关资源
      最近更新 更多