面向过程编程思想与匿名函数及其应用

一、面向过程

面向过程的编程思想

核心是过程二字:过程级流程,指的是解决问题先后先后顺序的步骤:先干啥,在干啥,接着干啥?

所以基于该思想编写程序就好比在设计一条流水线。

补充:无论哪种的编程范式设计出的程序, 最终的执行结果都是过程式的. 计算机底层的硬件的工作方式也是过程式的

优点:

降低程序程序的复杂度,将复杂的问题流程化,进而简单化

缺点:

程序的可拓展性极差,举例: 流水线的每道关卡都不可少, 不然影响整个流水线的运行.

面向过程的编程思想应用场景

前言

面向过程的编程思想一般用于功能一旦实现, 就很少需要改变的场景. 如果你要处理的任务是复杂的, 且现需要不断迭代更新和维护的, 那么面向过程的思想就不适用了.因此我们可以总结出以下两点:

  1. 不是所有的软件都需要频繁更迭: 编写脚本

  2. 即使一个软件需要频繁更迭, 也并代表这个软件所有的组成部分需要一起更迭: 登录注册的功能逻辑, djongo框架

二、编程范式

  • 编程范式指的是编程的套路

  • 主要的套路有三种:命令式编程, 函数式编程, 逻辑式编程

  • 常见的面向对象就是命令式编程, 常见的面向过程就是逻辑式编程

三、函数式

什么是函数式?

  • 函数式编程中的函数指的并不是编程语言中的函数(或方法)

  • 它指的是数学意义上的函数,将计算机的运算视为数学意义上的运算,即映射关系(如:y = f(x)),就是 y 和 x 的对应关系

函数式与逻辑式

  • 比起逻辑式,函数式更加注重的是执行结果并非执行的过程

  • 面向过程就是逻辑式

  • 函数式代表语言:Hashell, Erlang

补充:python提供的函数式编程特性

  • Python并不是一门函数式的编程语言,但却提供了很多函数式编程的特性

  • 比如 : lambda, max, min, map, reduce, filter

四、匿名函数(lambda)

什么是匿名函数?

  • 没有名字的函数

应用场景:

  • 临时用一次,通常用于与其他函数配合使用

匿名函数的强调点

  • 匿名函数的本质目的就是要没有名字,若给匿名函数赋值给一个名字事物没有意义的

  • 匿名函数的参数规则、作用域关系与有名函数是一样的

  • 匿名函数的函数体通常应该是一个表达式,该表达式必须要有一个返回值

匿名函数与有名函数对比

  • 有名函数

    # 有名函数,循环使用,保存了名字,通过名字就可以重复引用函数def foo(x,y):
        return x**y
    foo(2,3)  
    
  • 匿名函数

    #没有函数名,随时随地定义
    f = lambda x,y:x ** y
    print(f(2,4))  # 16
    # 一般配合应用 : max, min, sorted, map, reduce, filter
    

匿名函数的基本语法格式

lambda 参数1, 参数2, ..., 参数n: expression

匿名函数的调用方式

方式一:直接加括号就行

res = (lambda x, y: x + y)(7,8)
print(res)  # 15

方式二:给函数指定名字

f = lambda x,y:x ** y
print(f(2,4))  # 16
# 匿名函数的本质就是没有名字,这里指定名字是没有意义的(匿名函数只用于临时调用一次)
# 匿名函数一般用来与其他函数配合使用,以下来展开介绍

五、匿名函数的应用

求最大值与最小值

1.max( ) : 最大值

  • 接收两个参数 : ([可迭代对象],[函数])

  • 注意:第二个参数函数,必须指定关键字形式:key=匿名函数

2.min( ) : 最小值

  • 接收两个参数 : ([可迭代对象],[函数])

  • 注意:第二个参数函数,必须指定关键字形式:key=匿名函数

补充说明:

如果不指定参数: 使用默认方式迭代比较.( 如果迭代的对象是字典, 那么默认迭代方式的是字典的key, 由key作为本次函数的比较依据。)

指定参数: max与min会把迭代完毕以后的结果作为参数传给函数, 如果迭代的对象是字典,那么就会把字典迭代之后的结果。也就是字典的key当做参数。传给lambda函数赋值给定义的参数。然后以返回值作为比较依据

示例:

# 需求: 获取最大薪资或者最小薪资的那个人
salaries = {
    'siry': 3000,
    'tom': 7000,
    'lili': 10000,
    'jack': 2000
}
​
# 函数max会迭代字典salaries, 迭代字典默认取出的key会当作参数传给指定的匿名函数.
# 比较依据: 将函数的返回值 salaries[k] 返回, 作为比较依据
# 返回结果: 将比较完毕以后的的参数k当作返回值
res = max(salaries, key=lambda k: salaries[k])
print(res)  # lilires = min(salaries, key=lambda k: salaries[k])
print(res)  # jack

3.sorted( ) : 排序

注意:只能用于同种类型的数据排序,除了整型和字符串类型。如果是字符串排序,是以每个字符之间对应的ASCII码进行比较. 如果是列表与列表之间的排序, 是以每个元素作为比较

  • 接收三个参数 : ([可迭代对象],[函数],[排列顺序])

    • 注意:第二个参数函数,必须指定关键字形式:key=匿名函数

    • 第三个参数是排序顺序(默认从小到大reverse=False). 指定从大到小: reverse=True

  • 如果传入的可迭代对象是字典,默认是按照字典的key来进行排序的

    • sorted 函数会迭代可迭代对象中的每个元素, 把迭代后得到的值依次传给匿名函数

    • 如果是字典,那么迭代以后传给字典的就是 key, 最终,以匿名函数的返回值作为比较依据

    • 比如传入的是字典, 默认迭代的就是字典的 key, 那么返回的只就是字典的 key, 虽然你是用 value来进行比较的

  • reverse参数 : “False”代表从小到大, “True”代表的是从大到小

    #以每个人的薪资来做比较
    salaries = {
        'siry': 3000,
        'tom': 7000,
        'lili': 10000,
        'jack': 2000
    }
    # 默认是按照字典的key进行排序的.
    res = sorted(salaries)
    print(res)  # ['jack', 'lili', 'siry', 'tom'] -- > 字符串比较按照ASCII码比较: 'j'(106) < 'l'(108) < 's'(115) < 't'(116)# 需求: 按照薪资从小到大排序(默认升序 reverse=False)
    res = sorted(salaries, key=lambda k: salaries[k])
    # res = sorted(salaries, key=lambda k: salaries[k], reverse=False)
    print(res)  # ['jack', 'siry', 'tom', 'lili']# 需求: 按照薪资从大到小排序(reverse=True)
    res = sorted(salaries, key=lambda k: salaries[k], reverse=True)
    print(res)  # ['jack', 'siry', 'tom', 'lili']
    

运行原理

sorted函数会迭代可迭代对象中的每个元素, 把迭代后得到的值依次传给匿名函数, 如果是字典,那么迭代以后传给字典的就是key。最终,以匿名函数的返回值作为比较依据.排序完毕以后会返回默认迭代可迭代对象的方式。比如: 字典默认迭代的就是key。那么他就会以key作为你的返回值,虽然你比较的依据是字典的value。它的key是基于你value的排序结果排序的key。

map( ) : 映射

  • 接收两个参数 : ([函数],[可迭代对象])

  • 运行原理: map 函数遍历可迭代对象中的每个元素, 把遍历得到的值当做参数传给匿名函数, 以返回值的处理结果当做返回值返回

  • map得到的结果是迭代器对象

示例:

# 需求: 将array的每个元素做平方处理
array = [1, 2, 3, 4, 5]
res = map(lambda item: item ** 2, array)
print(res)  # map得到的结果是迭代器对象. 返回结果: <map object at 0x00000176D87AFDF0>
print(list(res))  # [1, 4, 9, 16, 25]# map的替代方案: 使用生成器表达式
res = (item ** 2 for item in array)
print(res)  # 得到的是一个生成器<generator object <genexpr> at 0x0000022EA48343C0>
print(list(res))  # [1, 4, 9, 16, 25]

reduce( ) : 合并

  • 接收三个参数 : ([函数],[可迭代对象],[初始值])

  • reduce 在python2中是内置函数, 在python3中被集成到模块 functools 中, 需要导入使用

  • 运行原理 : 以初始值作为第一个参数传给 x , 然后迭代传入的可迭代对象, 拿到的值 y 与 x 相加重新赋值给 x , 再次迭代取值, 周而复始, 直到迭代器被迭代完

示例:

# 需求: 对array进行合并求和运算
from functools import reduce
array = [1, 4, 9, 16, 25]
res = reduce(lambda x, y: x + y, array, 0)
print(res)  # 55# reduce的替代方案: sum
print(sum(array))  # 55# reduce的替代方案: 使用生成器表达式 + sum
salaries = {
    'siry': 3000,
    'tom': 7000,
    'lili': 10000,
    'jack': 2000
}
res = sum(value for value in salaries.values())
print(res)  # 22000# 验证(重点理解): 保留x的状态, 将每次y的值与x进行操作, 直至结束
li = [1, '2', '3', '4']
res = reduce(lambda x, y: x + y if isinstance(y, int) else x + int(y), li)
print(res)  # 10# 注意: x在初始阶段只被赋值一次, 并保留x的状态, 将每次y的值与x进行操作, 直至结束.
# (((10 - 1) - 2) - 3) = 4
res = reduce(lambda x, y: x - y, [1, 2, 3], 10)
print(res)
​
# ((1 - 2) - 3) = -4 
res = reduce(lambda x, y: x - y, [1, 2, 3])
print(res)

filten( ) : 过滤

  • 接收两个参数 : ([函数],[可迭代对象])

  • 遍历可迭代对象, 过滤出结果为真的元素, 如果是字典, 最终返回的结果是字典的 key

  • filten 返回的结果是迭代器

示例

# 需求: 对array进行过滤取出大于3小于16的数
array = [1, 4, 9, 16, 25]
res = filter(lambda item: 16 > item > 3 , array)
print(res)  # <filter object at 0x000001A219BEFDF0>print(list(res))  # [4, 9]# filter的替代方案: 使用生成器表达式
res = ()