【问题标题】:map with lambda vs map with function - how to pass more than one variable to function?带有 lambda 的映射与带有函数的映射 - 如何将多个变量传递给函数?
【发布时间】:2015-06-01 20:04:09
【问题描述】:

我想了解如何在 python 中使用 map,通过 google 搜索找到了 http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php,我发现这很有帮助。

该页面上的一个代码使用了一个 for 循环,并以一种有趣的方式将 map 放入该 for 循环中,map 函数中使用的列表实际上采用了 2 个函数的列表。代码如下:

def square(x): 
    return (x**2)

def cube(x):
    return (x**3)

funcs = [square, cube]

for r in range(5):
    value = map(lambda x: x(r), funcs)
    print value

输出:

[0, 0]
[1, 1]
[4, 8]
[9, 27]
[16, 64]

因此,在该教程的这一点上,我想“如果您可以使用动态函数 (lambda) 编写该代码,那么它可以使用使用 def 的标准函数编写”。所以我把代码改成这样:

def square(x): 
    return (x**2)

def cube(x):
    return (x**3)

def test(x):
    return x(r)

funcs = [square, cube]

for r in range(5):
    value = map(test, funcs)
    print value

我得到了与第一段代码相同的输出,但令我困扰的是变量r 取自全局命名空间并且代码不是严格的函数式编程。还有我被绊倒的地方。这是我的代码:

def square(x): 
    return (x**2)

def cube(x):
    return (x**3)

def power(x):
    return x(r)

def main():
    funcs = [square, cube]
    for r in range(5):
        value = map(power, funcs)
        print value

if __name__ == "__main__":
    main()

我玩过这段代码,但问题在于传递给函数def power(x)。我尝试了多种尝试传递到此函数的方法,但 lambda 能够自动将 x 变量分配给列表 funcs 的每次迭代。

有没有办法通过使用标准的def 函数来做到这一点,还是不可能,只能使用 lambda? 因为我正在学习 python,这是我的第一语言,我试图了解这里发生了什么。

【问题讨论】:

    标签: python lambda functional-programming map-function


    【解决方案1】:

    您可以将power() 函数嵌套在main() 函数中:

    def main():
        def power(x):
            return x(r)
    
        funcs = [square, cube]
        for r in range(5):
            value = map(power, funcs)
            print value
    

    所以r 现在再次从周围的范围中取出,但不是全局的。相反,它是一个 闭包 变量。

    但是,使用 lambda 只是另一种从此处的周围范围注入 r 并将其传递给 power() 函数的方法:

    def power(r, x):
        return x(r)
    
    def main():
        funcs = [square, cube]
        for r in range(5):
            value = map(lambda x: power(r, x), funcs)
            print value
    

    这里的r 仍然是一个非本地的,取自父作用域!

    您可以使用 r 作为第二个参数的默认值来创建 lambda:

    def power(r, x):
        return x(r)
    
    def main():
        funcs = [square, cube]
        for r in range(5):
            value = map(lambda x, r=r: power(r, x), funcs)
            print value
    

    现在r 作为默认值传入,因此它被视为本地值。但是对于您的 map() 而言,这实际上并没有什么不同。

    【讨论】:

      【解决方案2】:

      为什么不简单地将函数作为参数的一部分传递给power(),并使用itertools.product 创建所需的(value, func) 组合?

      from itertools import product
      
      # ...
      
      def power((value, func)):
          return func(value)
      
      for r in range(5):
          values = map(power, product([r], funcs))
          print values
      

      或者,如果您不希望/要求按函数对结果进行分组,而是想要一个平面列表,您可以简单地这样做:

      values = map(power, product(range(5), funcs))
      print values
      

      注意:签名 power((value, func))power() 定义为接受单个 2 元组参数,该参数会自动解压缩为 valuefunc

      相当于

      def power(arg):
          value, func = arg
      

      【讨论】:

        【解决方案3】:

        柯里化是另一种选择。因为两个参数的函数与一个参数的函数返回另一个接受剩余参数的函数相同,所以你可以这样写:

        def square(x):
            return (x**2)
        
        def cube(x):
            return (x**3)
        
        def power(r):
            return lambda(x): x(r) # This is where we construct our curried function
        
        def main():
            funcs = [square, cube]
            for y in range(5):
                value = map(power(y), funcs) # Here, we apply the first function
                                             # to get at the second function (which
                                             # was constructed with the lambda above).
                print value
        
        if __name__ == "__main__":
            main()
        

        为了使关系更明确一点,(a, b) -> c 类型的函数(该函数接受a 类型的参数和b 类型的参数并返回c 类型的值)相当于a -> (b -> c) 类型的函数。

        关于等价的额外内容

        如果您想更深入地了解这种等价性背后的数学原理,可以使用一些代数来了解这种关系。将这些类型视为代数数据类型,我们可以将任何函数 a -> b 转换为 ba 并将任何对 (a, b) 转换为 a * b。由于这种联系,有时函数类型被称为“指数”,而对类型被称为“乘积类型”。从这里,我们可以看到

        c(a * b) = (cb)a

        等等,

        (a, b) -> c  ~=  a -> (b -> c)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-30
          • 1970-01-01
          • 2017-06-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-03
          • 2018-12-18
          相关资源
          最近更新 更多