Skip to content
SRE运维进阶之路SRE运维进阶之路
github icon
    • 1 Python 简介

      • 1.1 初识Python
        • 1.2 Python 代码规范
          • 1.3 Python 虚拟环境
            • 1.4 使用 vscode 打造 python 开发环境
              • 1.5 pypi 配置国内镜像
              • 2 Python 基础

                • 2.1 Python基础语法
                  • 2.2 程序控制
                    • 2.3 Python数据类型

                      • 2.3.1 数值型
                        • 2.3.2 字符串 str
                          • 2.3.3 字节序列
                            • 2.3.4 列表 list & 元组 tuple
                              • 2.3.5 集合 set & 字典 dict
                            • 3 高级特性

                              • 3.1 线性结构特征 可迭代 & 切片
                                • 3.2 列表、集合、字典解析式
                                  • 3.3 生成器
                                    • 3.4 迭代器
                                    • 4 函数

                                      • 4.1 函数的定义 & 调用 & 返回值
                                        • 4.2 函数参数
                                          • 4.3 作用域
                                            • 4.4 递归函数
                                            • 5 函数式编程

                                              • 5.1 高阶函数
                                                • 5.2 返回函数
                                                  • 柯里化
                                                    • 函数作为返回值
                                                      • 闭包
                                                      • 5.3 匿名函数
                                                        • 5.4 装饰器
                                                          • 5.5 偏函数
                                                          • 6 模块

                                                            • 6.1 Python 模块常用的几种安装方式
                                                              • 6.2 Python 的 setup.py 详解
                                                              • 7 IO编程

                                                                • 7.1 操作文件和目录
                                                                  • 7.2 序列化和反序列化
                                                                  • 8 异常、调试和测试

                                                                    • 8.1 异常处理
                                                                    • 9 面向对象编程

                                                                      • 9.1 类、实例和封装
                                                                        • 9.2 访问控制和属性装饰器
                                                                          • 9.3 继承、多态和Mixin
                                                                          • 10 进程和线程

                                                                            • 10.1 多进程
                                                                              • 10.2 多线程
                                                                                • 10.2 线程同步
                                                                                • 11 网络编程

                                                                                  • 11.1 SocketServer
                                                                                    • 11.2 TCP 编程
                                                                                    • 11 魔术方法
                                                                                      • 17 IO 模型
                                                                                        • python 实际工作中的实例
                                                                                        • 前端学习笔记

                                                                                          5.2 返回函数

                                                                                          author iconClaycalendar icon2021年6月23日category icon
                                                                                          • Python
                                                                                          timer icon大约 3 分钟

                                                                                          此页内容
                                                                                          • 柯里化
                                                                                          • 函数作为返回值
                                                                                          • 闭包

                                                                                          # 5.2 返回函数

                                                                                          # 柯里化

                                                                                          • 指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数
                                                                                          • z = f(x, y) 转换成 z = f(x)(y) 的形式

                                                                                          例如

                                                                                          def add(x, y):
                                                                                              return x + y
                                                                                          
                                                                                          1
                                                                                          2

                                                                                          原来函数调用为 add(4, 5) ,柯里化目标是 add(4)(5) 。如何实现?

                                                                                          每一次括号说明是函数调用,说明 add(4)(5) 是2次函数调用。

                                                                                          add(4)(5)
                                                                                          等价于
                                                                                          t = add(4)
                                                                                          t(5)
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4

                                                                                          也就是说add(4)应该返回函数

                                                                                          def add(x):
                                                                                              def _add(y):
                                                                                                  return x + y
                                                                                              return _add
                                                                                          print(add(100)(200))
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5

                                                                                          通过嵌套函数就可以把函数转成柯里化函数。

                                                                                          # 函数作为返回值

                                                                                          高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

                                                                                          我们来实现一个可变参数的求和。通常情况下,求和的函数是这样定义的:

                                                                                          def calc_sum(*args):
                                                                                              ax = 0
                                                                                              for n in args:
                                                                                                  ax = ax + n
                                                                                              return ax
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5

                                                                                          但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数:

                                                                                          def lazy_sum(*args):
                                                                                              def sum():
                                                                                                  ax = 0
                                                                                                  for n in args:
                                                                                                      ax = ax + n
                                                                                                  return ax
                                                                                              return sum
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5
                                                                                          6
                                                                                          7

                                                                                          当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:

                                                                                          >>> f = lazy_sum(1, 3, 5, 7, 9)
                                                                                          >>> f
                                                                                          <function lazy_sum.<locals>.sum at 0x101c6ed90>
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3

                                                                                          调用函数f时,才真正计算求和的结果:

                                                                                          >>> f()
                                                                                          25
                                                                                          
                                                                                          1
                                                                                          2

                                                                                          在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

                                                                                          请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

                                                                                          >>> f1 = lazy_sum(1, 3, 5, 7, 9)
                                                                                          >>> f2 = lazy_sum(1, 3, 5, 7, 9)
                                                                                          >>> f1==f2
                                                                                          False
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4

                                                                                          f1()和f2()的调用结果互不影响。

                                                                                          # 闭包

                                                                                          注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。

                                                                                          另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。我们来看一个例子:

                                                                                          def count():
                                                                                              fs = []
                                                                                              for i in range(1, 4):
                                                                                                  def f():
                                                                                                       return i*i
                                                                                                  fs.append(f)
                                                                                              return fs
                                                                                          
                                                                                          f1, f2, f3 = count()
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5
                                                                                          6
                                                                                          7
                                                                                          8
                                                                                          9

                                                                                          在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。

                                                                                          你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:

                                                                                          >>> f1()
                                                                                          9
                                                                                          >>> f2()
                                                                                          9
                                                                                          >>> f3()
                                                                                          9
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5
                                                                                          6

                                                                                          全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。

                                                                                          返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

                                                                                          如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

                                                                                          def count():
                                                                                              def f(j):
                                                                                                  def g():
                                                                                                      return j*j
                                                                                                  return g
                                                                                              fs = []
                                                                                              for i in range(1, 4):
                                                                                                  fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
                                                                                              return fs
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5
                                                                                          6
                                                                                          7
                                                                                          8
                                                                                          9

                                                                                          再看看结果:

                                                                                          >>> f1, f2, f3 = count()
                                                                                          >>> f1()
                                                                                          1
                                                                                          >>> f2()
                                                                                          4
                                                                                          >>> f3()
                                                                                          9
                                                                                          
                                                                                          1
                                                                                          2
                                                                                          3
                                                                                          4
                                                                                          5
                                                                                          6
                                                                                          7

                                                                                          缺点是代码较长,可利用lambda函数缩短代码。

                                                                                          edit icon编辑此页open in new window
                                                                                          上次编辑于: 2021/6/23 03:47:00
                                                                                          贡献者: clay-wangzhi
                                                                                          上一页
                                                                                          5.1 高阶函数
                                                                                          下一页
                                                                                          5.3 匿名函数
                                                                                          备案号:冀ICP备2021007336号
                                                                                          Copyright © 2023 Clay