Python之函数式编程(一)

##要点
什么是函数式编程
函数式编程的语法使用
函数式编程的设计思想
函数式编程的应用场景
函数式编程之lambda
函数式编程之高阶函数

什么是函数式编程

函数:function。
函数式:functional,一种编程范式。函数式编程是一种抽象计算机的编程模式。
函数!= 函数式(如计算!=计算机)
  函数式编程是通过一系列函数来解决问题,其主要特征在于:函数可以赋值给变量,赋值后变量绑定函数;允许将函数作为参数传入另外一个函数;允许函数返回一个函数。一般情况下,可以将函数作为参数或者返回值进行解决问题。

函数式编程的语法使用

  在了解函数式编程语法之前,我们可以先回顾一下正常函数的定义与调用过程:

def func01():
    print("func01可以执行")
# 测试代码
func01()

  从这个代码可以看出,通过测试代码进行调用func01,并执行函数体中的代码块,如果有返回值,则将返回值赋值为=给待接收的变量,以此实现函数调用。而在函数式编程中,是将函数变量直接由变量进行接收,如下代码:

def func01():
    print("func01可以执行")
# 将函数赋值给变量
a = func01
# 测试代码
func01()
# 通过变量调用函数
a()

  从以上的代码区可以看出,函数式编程是通过a=func01这个语句,将func01这个函数赋值给变量a,由a去存储函数func01的内存地址;因此,使其可以能够通过a去调用函数体。那么这边是否我们可以再根据python中变量的特性(变量可指万物),让变量a去尽可能地去指向我们所需要的函数实现相应的功能。
  通过这个问题的抛出,我想大家也不难想到在一个函数中通过一个参数进行接收,并在函数体中通过参数进行调用,代码如下:

def func01():
    print("func01可以执行")

def func02():
    print("func02可以执行")

# func03
def func03(b):
    print("func03执行喽")
    b()
# 测试代码
func03(func01)
func03(func02)

  从上述代码上,大家不难看出,通过调用func03函数时,以函数func01,func02进行实参传入func03函数,作为形参b进行接收,并在函数体中进行调用func01函数,或者其他函数。而这个其实就是函数式编程语法的设计所在。

函数式编程的设计思想

  其实,通过上面的介绍,大家可能有所熟悉,这种以形参的方式来接收函数进行调用其他函数在面向对象的三大特性中也有所体现,尤其是在不同类之间的跨类调用上面。虽然是不同实现方式,但是,从设计思想看,可以说是在一定程度上师出一家。
  同样,以一个例子引入,

list01 = [4, 45, 54, 656, 6, 7, 78]

# 定义函数,查找所有偶数
def find01():
    for item in list01:
        if item % 2 == 0:
            yield item

# 定义函数,查找所有大于10的
def find02():
    for item in list01:
        if item > 10:
            yield item

  从这个例子中,需要定义函数分别去设计查找列表中为偶数的内容、列表中所有大于10的函数。那么,可以看到,这俩个函数有除了判断条件不一致外,其他的内容完全一致,这也在一定程度上加大了代码的冗余。如果倘若把判断条件抽象为一个函数,需要时直接调用,这样也可在一定程度上提升代码的复用性。那么这个时候就可以用到我们刚刚所说的函数式编程,优化代码如下:

def condition01(item): 
    return item % 2 == 0

def condition02(item): 
    return item > 10

def find(func): 
    for item in list01:
        # if item > 10:
        # if condition02(item):
        if func(item):  
            yield item
# 测试代码
find(condition01)  

  如上述代码,将条件抽象为函数,并将以提取出的函数名以参数形式传入主函数,如此实现函数设计。根据刚刚研究的思路,我们是发现了其大致相同的函数体,不同的判断条件,因此选择提取方法,传入参数,达到复用。不错,这个也正是函数式编程思想的设计所在。其思想步骤主要包含以下步骤:
(1)将变化的核心算法单独定义为函数
(2)使用参数隔离具体核心算法
(3)传递具体的核心算法

  而函数式编程的设计思想,与面向对象的三大特性特性的设计思想如出一辙。逃不过“分(封装)、隔(继承)、做(多态)”,面向对象的设计思想在之后的内容有所讲到。

函数式编程的应用场景

  聊完函数式编程的设计思想之后,那么它本身的实用性也就能够凸显出来,没错,就是对于相同的业务场景或者实现方式,对其实现方式进行提取,以封装为一个函数,以便以后调用。这样,一方面可以提升开发人员的开发效率,另一方面,也可以降低函数之间的耦合度,以方便对以后业务的优化。

函数式编程之lambda

  从上面的代码可以看到,我们需要对判断条件进行提取,虽然大大降低了耦合度,但是函数在第一次书写时还是比较麻烦的。由此,lambda表达式就出现了。lambda是将提取的函数中的核心逻辑传入方法体,也是一种匿名方法。这样一来,lambda作为参数传递时语法更加简洁,代码的可读性强;同时,可以随时创建和销毁,程序之间的耦合度也大大降低。
语法
定义:
  变量 = lambda 形参: 方法体
调用:
  变量(实参)
注意:
(1)形参没有可以不填
(2)方法体只能有一条语句,且不支持赋值语句。(这也是之所以语法简单的原因)
常见的设计形式
(1)有参数,有返回值

def func01(p1, p2):
    return p1 > p2
# 调用函数
func01(1, 2)
# 转换为lambda表达式:
func01 = lambda p1, p2: p1 > p2
# 调用函数
func01(1, 2)

(2)无参数,有返回值

def func02():
    return 250
# 调用函数
print(func02())
# 转换为lambda表达式:
func02 = lambda: 250
print(func02())

(3)有参数,无返回值

def func03(p1):
    print("传入的是", p1)
# 转换为lambda表达式:
func03 = lambda p1: print("传入的是", p1)
func03(1)

(4)无参数,无返回值

def func04():
    print("我爱编程")

func04()
# 转换为lambda表达式:
func04 = lambda: print("我爱编程")
func04()

函数式编程之高阶函数

  当然,Python在函数式编程中,也内置了一些常用的高阶函数,以方便我们能够更好地去使用函数式编程。
(1)map(函数,可迭代对象)
使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。其作用就是对一个集合中的每个元素做处理,生成一个新的元素,由这些新的元素组成一个新的集合的返回。举例说明:

>>> def double(a):
...     return a*2
...
>>> map(double,range(5))
[0, 2, 4, 6, 8]
# 或者通过lambda实现
>>> map(lambda a:a*2,range(5))

  此外,需要注意的是,当函数为None时,返回值为原来可迭代对象;但对于多个集合,返回一个集合(集合中每个元素为元组)。

>>> arr = [1,2,3]
>>> newarr = map(None,arr)
>>> print arr
[1, 2, 3]
>>> print newarr
[1, 2, 3]

>>> map(None,[1,2,3],['a','b'])
[(1, 'a'), (2, 'b'), (3, None)]

  使用Map函数,可以让我们编写代码时把精力集中中如何转换元素上,不用关心集合的边界,不用关心新集合的创建等。这正是函数式编程的优势和典型特点所在。
(2)filter(函数,可迭代对象):
根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。将函数作用于迭代器的每个元素,如果返回true,则将结果加到最后输出,否则过滤掉

list1=list(filter(lambda x:x%2==0,range(1,11)))

(3)sorted(可迭代对象,key = 函数,reverse = bool值)
sorted对于所有的可迭代对象都可进行排序,将返回值为排序结果。在这里需要对比一下列表中sort()方法,对于排序sort是在list的原址上进行排序排序的,而sorted返回的是一个已经排好序的***副本***(新的可迭代对象),其原址Iterable的序列并没有变化。
sorted的参数设置
sorted(Iterable,func,reverse)
具体参数设置如下:
①Iterable是带排序的可迭代对象
②func其对应一个函数,该函数作用于可迭代对象的每个值上,并返回函数操作的结果排序是根据每个迭代数值返回的结果排序,但排序返回的结果还是原来list中的元素。
③reverse 有两个值:reverse=True和reverse=False,分别指示对Iterable的排序是按倒序和顺序来排列,默认为False,即按照顺序排列。

tuple_number = ([1, 1], [2, 2, 2], [3, 3, 3, 3], [4])
for item in sorted(tuple_number, key=lambda e: e*2, reverse=True):
    print(item)

(4)max(可迭代对象,key = 函数) 和 min(可迭代对象,key = 函数)
(5)reduce(函数,可迭代对象)
先将itr(迭代器)里面的前两个值传递给函数f,计算出结果,然后再同第三个值通过f计算出结果。一直迭代,直到没有其他值为止。需要注意的是,reduce不在python的内置模块中,在functools中。如下例子:

# 定义一个比大小的函数
from functools import reduce
def max(x, y):
    if x > y:
        return x
    else:
        return y
        
# reduce返回其中的最大值
print(reduce(max, [1, 3, 5, 3, 1]))

  下一章是对函数式编程中闭包的使用以及装饰器的理解,一方面可以帮助自己整理思路,另一方面也希望可以让各位查阅的小伙伴给出建议,以期后续完善。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值