• Python自动化开发


    本节内容

    一、函数式编程

    二、高阶函数

      1、变量可以指向函数

      2、函数名也是变量

      3、传入函数

    三、返回函数

      1、函数作为返回值

      2、闭包特性

    一、函数式编程

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,

    这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元

    我们首先要搞明白计算机(Computer)和计算(Compute)的概念。

    在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。

    而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。

    对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;

    越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,

    因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用

    而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的

    函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数

    Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

    二、高阶函数

    高阶函数 Higher-order function

    1、变量可以指向函数

    print(abs(-10))  # 调用绝对值函数
    print(abs)       # 函数本身
    
    x = abs(-10)     # 函数返回值 10 赋给变量 x,
    
    f = abs          # 函数本身赋值给变量 f ,即变量可以指向函数
    print(f(-10))    # 输出结果为 10
    
    # 说明变量 f 已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同

    2、函数名也是变量

    函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数

    abs = 10
    
    print(abs)       # 输出结果  10
    print(abs(-10))  # 错误信息 TypeError: 'int' object is not callable
    

     abs指向10后,就无法通过abs(-10)调用该函数了!因为abs这个变量已经不指向求绝对值函数而是指向一个整数10!

    3、传入函数

    既然变量可以指向函数,函数的参数能就收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

    def add(x, y, f):
        return f(x) + f(y)
    
    add_sum = add(-10, 10, abs)  # x=-10 y=10 f=abs
    print(add_sum)
    

    编写高阶函数,就是让函数的参数能够接收别的函数

    三、返回函数

    1、函数作为返回值

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

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

    def calc_sum(*args):
        ax = 0
        for n in args:
            ax += n
        return ax
    

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

    def lazy_sum(*args):
        def inner_sum():
            ax = 0
            for n in args:
                ax += n
            return ax
        return inner_sum    # 定义时,返回相应函数
    
    f1 = lazy_sum(1, 3, 5, 7, 9)  # 调用函数lazy_sum,返回值为函数inner_sum
    f2 = lazy_sum(1, 3, 5, 7, 9)  # 调用函数lazy_sum,返回值为函数inner_sum
    
    print(f1)        # <function lazy_sum.<locals>.inner_sum at 0x000000B2C801C510>,返回值为函数 inner_sum
    print(f1 == f2)  # False, 说明 f1和f2是独立的
    
    print(f1())      # 调用函数f1,返回值为求和结果
    print(f2())      # 调用函数f2,返回值为求和结果
    

    在这个例子中,我们在函数lazy_sum中又定义了函数calc_sum,并且,内部函数calc_sum可以引用外部函数lazy_sum的参数和局部变量,

    lazy_sum返回函数calc_sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

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

    2、闭包特性

    注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

    闭包用起来简单,实现起来可不容易。

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

    def count():
        fs = []
        for i in range(1, 4):
            def func():
                return i*i
            fs.append(func)  # 把函数名func,添加到列表fs
        return fs           # 返回值为列表
    
    print(count())  # 列表,其中元素为函数func
    f4, f5, f6 = count()    # 把列表元素依次赋给f4,f5,f6
    print("f4(): ", f4())  # 调用函数func(),返回 i*i,结果为9
    print("f5(): ", f4())  # 调用函数func(),返回 i*i,结果为9
    print("f4(): ", f4())  # 调用函数func(),返回 i*i,结果为9

    在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了,实际的返回结果都为9

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

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

  • 相关阅读:
    c# 合并byte数组
    DataGridView扩展方法行号、全选、导出到Excel(引用excel组件、生成html两种方式)
    c#利用zlib.net对文件进行deflate流压缩(和java程序压缩生成一样)
    TSQL查询笔记4: FROM T1,T2与联接的区别
    “菜鸟”程序员和“大神”程序员差距在哪里
    JAVA:模板方法模式
    Windows检测到一个硬盘问题?
    照我思索,你的电脑百毒不侵 (转)
    JAVA:多态
    HTML与CSS(图解4):表格
  • 原文地址:https://www.cnblogs.com/jonathan1314/p/6392712.html
Copyright © 2020-2023  润新知