Python函数式编程(python系列27)

2024-01-08 18:53:21

前言:函数式编程有什么用,为什么要学函数式编程?函数式编程是一种编程范式,可减少程序的错误和复杂度,提高代码的可维护性和可重用性。

1.定义:用一系列函数解决问题

? ? ? ? 函数可以赋值给变量,赋值后变量绑定函数。

? ? ? ? 允许将函数作为参数传入另一个函数。

2.高阶函数:将函数作为参数或返回值的函数

函数作为参数

将核心逻辑传入方法体,使该方法的适用性更广,体现了面向对象的开闭原则

那什么是开闭原则呢?

对扩展开放,对修改封闭。

当软件系统需要进行功能扩展时,应该可以通过增加新的代码来实现,而不是修改已有的代码。开闭原则的核心思想是面向接口编程,通过抽象和封装来实现代码的可扩展性和可维护性。开闭原则和前面所提到的先确定用法后决定做法如出一辙,用法不能修改,但是能新加做法。

假如现在有两个需求:

1.定义函数,在列表中查找第一个奇数

2.定义函数,在列表中查找第一个能被3或5整除的数字

不使用函数式编程思想来实现:

# 不使用函数式编程思想
# 1.定义函数,在列表中查找第一个奇数
def find_first_odd(numbers):
    for number in numbers:
        if number % 2 != 0:
            return number


# 2.定义函数,在列表中查找第一个能被3或5整除的数字
def find_first_divisible(numbers):
    for number in numbers:
        if number % 3 == 0 or number % 5 == 0:
            return number


if __name__ == '__main__':
    list_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    print(find_first_odd(list_num))  # 1
    print(find_first_divisible(list_num))  # 3

上述代码当然能实现我们提到的两个需求,可当我们的功能增加,查找列表中第一个偶数,我们则有需要定义一个函数。可我们发现其实这些需求的主体逻辑相同,核心算法不同,这个时候我们就可以抽象主题逻辑创建一个适用性更广的函数,再将核心算法通过参数传递给主题逻辑函数,而这个被抽象化的主题逻辑函数被称为高阶函数。高阶函数是早就写好的不能修改,是闭,而核心算法是当下决定实现的扩展功能,属于开,这也体现了面向对象的开闭原则。

使用函数式编程的思想实现:

# 使用函数式编程思想
# 抽象相同的主题结构,创建一个高阶函数
def find_single(iterable, condition):
    for item in iterable:
        if condition(item):
            return item


def find_first_odd(number):
    return number % 2 == 1


def find_first_divisible(number):
    return number % 3 == 0 or number % 5 == 0


if __name__ == '__main__':
    list_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    print(find_single(list_num, find_first_odd))  # 1
    print(find_single(list_num, find_first_divisible))  # 3

用为主题逻辑相同,核心算法不同

所以使用函数式编程思想(分,隔,做)

分:将主题逻辑和核心算法分开

隔:将核心算法使用形参代替

做:将想要实现的需求的核心算法做出来

上述的代码中的核心算法非常简单,但是还需要给它定义函数名,显得非常的麻烦,应该如何解决呢?lambda 表达式,匿名方法

lambda表达式

定义:是一种匿名方法

作用:

作为参数传递时语法简洁,优雅,代码可读性强。

随时创建和销毁,减少程序耦合度。

语法:

变量 = lambda 形参:方法体

调用:变量(实参)

限制:形参没有可以不填,方法体只能有一条语句,且不支持赋值语句。

有了lambda我们再来优化我们上面的代码吧:

# 使用函数式编程思想
# 抽象相同的主题结构,创建一个高阶函数
def find_single(iterable, condition):
    for item in iterable:
        if condition(item):
            return item


if __name__ == '__main__':
    list_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    print(find_single(list_num, lambda x: x % 2 == 1))  # 1
    print(find_single(list_num, lambda x: x % 3 == 0 or x % 5 == 0))  # 3

一般我们都将自定义的高阶函数封装起来:

from common.iterable_tools import IterableHelper


if __name__ == '__main__':
    list_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    print(IterableHelper.find_single(list_num, lambda x: x % 2 == 1))  # 1
    print(IterableHelper.find_single(list_num, lambda x: x % 3 == 0 or x % 5 == 0))  # 3
# common -> iterable_tools.py
"""
    对可迭代对象的常用操作
"""


class IterableHelper:
    """
        可迭代对象助手:封装对可迭代对象常用的高阶函数
        集成操作框架
    """

    @staticmethod  # 静态方法:不让python解释器自动为第一个参数传递self
    def find_single(iterable, condition):
        """
            在可迭代对象中查找第一个满足条件的元素
        :param iterable:可迭代对象
        :param condition:函数类型,一个参数,一个bool返回值
        :return:第一个满足条件的元素
        """
        for item in iterable:
            if condition(item):
                return item

在工作中,或者在学习中我们自定义的通用工具都应该封装起来,提高工作效率。

内置高阶函数

map(函数,可迭代对象):使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。

filter(函数,可迭代对象):根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。

sorted(可迭代对象,key = 函数,reverse = bool值):排序,返回值为排序结果。

max(可迭代对象,key = 函数):根据函数获取可迭代对象的最大值

min(可迭代对象,key = 函数):根据函数获取可迭代对象的最小值

大家要学会举一反三,我们刚才自己写了高阶函数,面对祖师爷给我们写的内置高阶函数我们也应该使用,并能模拟出能实现相同功能的高阶函数。

大家可以来写一些高阶函数:

my_map, my_filter, my_sorted, my_max, my_min

实现和对应内置高阶函数相同的功能。

函数作为返回值

逻辑连续,当内部函数被调用时,不脱离当前的逻辑。

闭包

三要素:外中有内,内使用外,外返回内。

代码案例:

#  闭包案例
def func01():
    print("func01")
    a = 10

    def func02():
        print("func02")
        print(a)

    return func02


if __name__ == '__main__':
    condition = func01()  # func01
    condition()  # func02 10

上面代码它包含了闭包三要素,它是一个闭包。

优点:内部函数可以使用外部变量

缺点:外部变量一直存在于内存中,不会在调用结束后释放,占用内存。

作用:实现python装饰器

装饰器原理:

#  装饰器


def new(func):
    def wrapper(*args, **kwargs):
        print('我是新功能')
        res = func(*args, **kwargs)
        return res
    return wrapper


def old(a, b, c):
    print('我是旧功能')
    print(a, b, c)
    return '执行旧功能成功'


old = new(old)
old()



上面代码,在不修改旧功能的前提下,在每次执行旧功能时都会先执行新功能。

上面是原理,在实际开发中我们一般写成这样

#  装饰器


def new(func):
    def wrapper(*args, **kwargs):
        print('我是新功能1')
        res = func(*args, **kwargs)
        return res

    return wrapper


def new2(func):
    def wrapper(*args, **kwargs):
        print('我是新功能2')
        res = func(*args, **kwargs)
        return res

    return wrapper


@new2
@new
def old(a, b, c):
    print('我是旧功能')
    print(a, b, c)
    return '执行旧功能成功'


old(1, 2, 3)

使用@函数装饰器名称来修饰原函数

一个函数可以被多个装饰器修饰,执行顺序为从近到远。

文章来源:https://blog.csdn.net/a12345dfsdf/article/details/135229531
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。