【问题标题】:Is it possible to call a function (not a built in function) inside a list comprehension in python?是否可以在 python 的列表理解中调用函数(不是内置函数)?
【发布时间】:2014-08-23 18:46:17
【问题描述】:

假设我们有一个列表:

X = [1,2,3,4,5,6,7,8]

我们创建了一个名为 add() 的函数:

def add():
  sum = 0
  result = 0
  for e in X:
    sum = sum + e
    return sum
add()

遍历数字 X 的列表,将列表中的下一个元素添加到前一个总和中。所以对于每个元素 X[i],我们有:

1
3
6
10
15
21
28
36
45

现在,如果我想通过使用列表推导式再次将这些结果放入列表中怎么办。是否可以在列表理解中调用诸如 add() 之类的函数, 考虑到可以在列表推导中应用内置函数吗?

我尝试了以下方法:

L = [add() for e in X]
print L

给了

[None, None, None, None, None, None, None, None, None]

而不是

[1,3,6,10,15,21,28,36,45]

为什么我在这个列表中得到 NoneType 值?

【问题讨论】:

  • 我不确定单个 add() 调用如何产生多个值。
  • 这里出了点问题 - add() 函数只返回一个值,并且每次都应该相同(因为 X 没有被修改)。你确定你在add() 中有return 而不是print
  • 您的 for 循环在第一次迭代时返回。
  • 我得到的是[1, 1, 1, 1, 1, 1, 1, 1];你确定你使用了正确的add() 函数吗?

标签: python function list-comprehension nested


【解决方案1】:

您可以使用 yield 执行此操作以保持原始格式:

    X = [1,2,3,4,5,6,7,8]

    def add():
      sum = 0
      for e in X:
        sum = sum + e
        yield sum

    L = [value for value in add()]
    print L

【讨论】:

  • L = [value for value in add()] 在这种情况下看起来会更清晰。
  • 我还建议更改add() 以将X 作为参数。
【解决方案2】:

是的,可以在列表推导中调用函数。您的示例很好 - 应该归咎于 add() 函数。 您需要的是让 add() 函数接收一个参数 - 要求和的列表。

def add(elements):
    sum = 0
    for el in elements:
        sum += el
    return sum

这样,列表解析将如下所示:

L = [add(X[:i+1]) for i in xrange(len(X))]
[1, 3, 6, 10, 15, 21, 28, 36]

这相当于:

L = [add(X[:1]), add(X[:2]), ..., add(X[:8])]

结果是一个前缀和列表 - 你想要的东西。

【讨论】:

    【解决方案3】:

    您的方法行不通,因为您的 add() 是无状态的。您需要在 add() 的不同调用之间保持状态,否则 add() 将始终产生相同的输出。

    实现您想要的一个解决方案是itertools.accumulate()。请参阅Equivalent of Haskell scanl in python 进行讨论。

    此处的其他答案建议使用涉及range() 的列表理解。虽然这样可行,但效率也很低,因为它是一种 O(n^2) 算法,会从头开始重新计算每个条目的累积和。

    【讨论】:

    • 您是说列表 X 会因此而被修复?你能澄清一下你的意思吗?
    • 我的意思是每次调用add()都会产生相同的输出,因为它不带参数,不执行突变,并且通常是无状态的。 klasske 建议将 return 更改为 yield 有效,因为生成器确实保持状态。
    【解决方案4】:
    #!/usr/bin/env python
    """
    produce a list that adds each item to the previous item
    this list [1,2,3,4] will produce this list [1,3,6,10]
    """
    
    def accumulate(my_list, previous = 0):
        for i in my_list:
            previous += i
            yield previous
    
    x = [1,2,3,4,5,6,7,8,9]
    new_list = []
    new_list = [i for i in accumulate(x)]
    print x   
    print new_list
    

    产生这个:

    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    [1, 3, 6, 10, 15, 21, 28, 36, 45]
    

    【讨论】:

      【解决方案5】:

      是的,可以调用列表解析中的任何函数。

      另请注意,在 Python 2.x 中,您不能在列表解析中使用 print,因为 print is not a function(在 Python 2 中)。

      对于您的示例 - 它可能看起来像这样,使用与共享状态(s 变量)一起使用的 add() 函数:

      s = 0   # better not use name 'sum' as it is already a builtin function
      def add(i):
          global s
          s += i
          return s
      X = [1, 2, 3, 4, 5, 6, 7, 8]
      print [add(i) for i in X]
      # prints [1, 3, 6, 10, 15, 21, 28, 36]
      # but beware the global shared state! for example when called again:
      print [add(i) for i in X]
      # prints [37, 39, 42, 46, 51, 57, 64, 72]
      

      查看其他答案如何在没有该共享状态的情况下执行此操作,因此当您忘记设置 s = 0 时不会得到不同的结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-25
        • 2023-02-08
        • 2017-12-08
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多