【问题标题】:Partially applied List Comprehension部分应用列表理解
【发布时间】:2014-07-14 10:14:17
【问题描述】:

我开始学习 Haskell,事实证明,在那里,您可以使列表推导式成为部分应用的函数。换句话说,它返回一个接受列表的函数,然后在列表上运行列表推导。

例子:

boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]

boomBangs can then be called with the actual "xs" argument.

我的问题:有没有办法在 Python 中做到这一点?我四处寻找,找不到路,但我可能遗漏了一些东西。

能够做到这一点非常有价值。

编辑:

我的意思似乎有些混乱。

我希望能够定义列表理解而不必给它提供列表以处理直到以后。

这个想法是,列表推导实际上变成了一个接受一个参数的函数,即要处理的列表。

例如我可以这样做:

my_new_func = [x*2 for x in l] # l is **not defined**

然后在代码后面的某个地方:

my_new_func(range(10)) # Returns the answer

这是一种非常好的函数式编程方式。

第二次编辑:

这是一种做我想做的事情的方法,但我想知道是否有更好的方法:

boomBangs = lambda lst: [actual list comprehension]

boomBangs(range(10))

【问题讨论】:

  • 你不能只做一个接受列表并做你需要做的函数吗?
  • @SukritKalra 我宁愿避免为此创建一个函数,这个想法是为了让语法更容易。有关您的建议,请参阅我的第二次编辑。
  • 不幸的是,Python 没有提供您正在寻找的那种列表解析(在 Haskell 中已经找到)。创建一个 lambda 或一个函数将是这里的方法。
  • Haskell 代码创建了一个函数。我错过了什么?
  • 是的,boomBangs xs = ... 只是定义函数的 Haskell 符号;例如addOne x = x + 1。与部分应用无关。

标签: python haskell functional-programming list-comprehension


【解决方案1】:

特别之处不是列表推导,而是函数定义。恰好该函数返回一个列表。因此,只需将其定义为 Python 中的普通函数即可。

boomBangs = lambda xs: ["BOOM!" if x < 10 else "BANG!" for x in xs if odd(x)]

def boomBang(xs):
  return ["BOOM!" if x < 10 else "BANG!" for x in xs if odd(x)]

如果您需要它变得懒惰,请改用genex。

boomBangs = lambda xs: ("BOOM!" if x < 10 else "BANG!" for x in xs if odd(x))

def boomBang(xs):
  return ("BOOM!" if x < 10 else "BANG!" for x in xs if odd(x))

【讨论】:

    【解决方案2】:

    你可以使用python的列表推导:

    xs = ["BOOM!" if x < 10 else "BANG!" for x in range(20) if x % 2 == 1]
    

    将其合并到一个函数中:

    def boombang(xs):
        return ["BOOM!" if x < 10 else "BANG!" for x in xs if x % 2 == 1]
    

    你也可以使用lambda:

    >>> boombang = lambda xs: ["BOOM!" if x < 10 else "BANG!" for x in xs if x % 2 == 1]
    >>> boombang(range(-10, 20))
    ['BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BANG!', 'BANG!', 'BANG!', 'BANG!', 'BANG!']
    >>> 
    

    列表推导向后工作,定义在结束,语句在开始。在这个列表解析的开头,我们说"BOOM!" if x &lt; 10 else "BANG!",翻译成:

    if x < 10:
        xs.append("BOOM!")
    else:
        xs.append("BANG!")
    

    在第二部分中,我们将 x 定义为从 0 到 20 的数字列表中的每个项目,包括 0 到 20。之后,我们使用 python 的模数确保这个循环只有在 x 是奇数时才会完成。


    >>> xs = ["BOOM!" if x < 10 else "BANG!" for x in range(20) if x % 2 == 1]
    >>> xs
    ['BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BANG!', 'BANG!', 'BANG!', 'BANG!', 'BANG!']
    >>> 
    

    【讨论】:

      【解决方案3】:

      您可以使用内置函数mapfilterfunctools.partial 以您正在寻找的风格实现此目的,但与将 Python 函数作为其他海报都做过。但是,部分应用和柯里化确实是可以在 Python 中使用的强大技术。

      en.wikipedia.org/wiki/Partial_application

      en.wikipedia.org/wiki/Currying

      这可以使用toolz Python 包轻松演示,该包包含许多其他函数式编程语言中常见的功能实用程序。 toolz 也有一个方便的 curried 命名空间,我将使用它来重现您的示例:

      >>> # define our primitive functions for clarity
      >>> boombang = lambda x: "BOOM!" if x < 10 else "BANG!"
      >>> is_odd = lambda x: x % 2 == 1
      
      >>> # given a list, using built-in functions we can do
      >>> map(boombang, filter(is_odd, range(20)))
      ['BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BANG!', 'BANG!', 'BANG!', 'BANG!', 'BANG!']
      
      >>> # if we want to provide the list later, we can do
      >>> from toolz.curried import map, filter, compose
      >>> boomBangs = compose(map(boombang), filter(is_odd))
      
      >>> # ... Now we have our input list, so let's use it!
      >>> list(boomBangs(range(20))
      ['BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BOOM!', 'BANG!', 'BANG!', 'BANG!', 'BANG!', 'BANG!']
      

      请注意,在最后一个示例中,我们如何只将单个参数传递给 mapfilter。这是咖喱!当提供最后一个参数时,函数会被调用,我们确实得到了相同的结果。

      让我们分别使用mapfilter 来澄清发生了什么:

      >>> from toolz.curried import map, filter
      >>> map_boombang = map(boombang)
      >>> list(map_boombang([9, 10, 11]))
      ['BOOM!', 'BANG!', 'BANG!']
      
      >>> filter_odd = filter(is_odd)
      >>> list(filter_odd(range(10)))
      [1, 3, 5, 7, 9]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-10
        • 1970-01-01
        • 1970-01-01
        • 2013-07-08
        • 1970-01-01
        • 2018-08-06
        • 2022-06-16
        • 2014-03-16
        相关资源
        最近更新 更多