python函数式编程

这篇博客探讨了Python中的函数式编程,包括lambda函数的定义和使用,以及闭包的概念。通过示例展示了如何利用lambda函数进行匿名计算,如在列表排序中的应用,并解释了闭包如何在函数内部保持变量状态。此外,还讨论了Python中的函数式编程特性,如map、reduce、filter等内置函数的使用,以及列表解析、字典解析和生成器等语法。
摘要由CSDN通过智能技术生成

Python中定义函数有两中方法,一种式用常规方式def定义,函数要指定名字,第二种式用lambda定义,不需要指定名字,不需要指定名字,称为Lambda函数。
Lambda函数又称匿名函数,有些时候只需要临时一用,而且业务逻辑简单,就可以使用Lambda匿名函数,没有必要非给取个名字。
先来看个简单的lambda函数

>>> lambda x, y: x + y
<function __main__.<lambda>>

x和y式函数的两个参数,冒号后面的表达式是函数的返回值,你可以一眼看出这个函数就是在求两个变量的和,但作为一个函数,没有名字如何使用呢?这里我们暂且给这个匿名函数绑定一个名字,这样使得我们调用匿名函数成为可能。

>>> add = lambda x, y: x + y
>>> add
<function __main__.<lambda>>
>>> add(1, 2)
3

它等同于常规函数

>>> def add2(x, y):
        return x + y
>>> add2
<function __main__.add2>
>>> add2(1, 2)
3

但是,如果定义了匿名函数,还要给它绑定一个名字的话,有点画蛇添足,通常是直接使用lambda函数。那么lambda函数的正确使用场景在哪呢?

1、函数式编程

尽管Python算不上是一门纯函数式编程语言,但它本身提供了很多函数式编程的特性,像map、reduce、filter、sorted这些函数都支持函数作为参数,lambda函数可以应用在函数式编程中。
请看题:一个整数列表,要按照列表中元素的绝对值大小升序排列,你会怎么做?

>>> list1 = [3, 5, -4, -1, 0, -2, -6]
>>> sorted(list1, key = lambda x: abs(x))
[0, -1, -2, 3, -4, 5, -6]

排序函数 sorted 支持接收一个函数作为参数,该参数作为sorted的排序依据,这里按照列表元素的绝对值进行排序,当然,我们也可以使用普通函数来实现:

>>> def foo(x):
        return abs(x)
>>> sorted(list1, key=foo)
[0, -1, -2, 3, -4, 5, -6]

只不过是这种方式的代码看起来不够Pythonic而已。

2、闭包

闭包本身是一个晦涩难懂的概念,它可以专门单独用一篇文章来介绍,不过在这里我们可以简单粗暴地理解为闭包就是一个定义在函数内部的函数,闭包使得变量即使脱离该函数的作用域范围也依然能被访问到。
来看一个用lambda函数作为闭包的例子:

>>> def my_add(n):
        return lambda x: x + n

>>> add_1 = my_add(3)
>>> add_1(7)
10

这里的lambda函数就是一个闭包,在全局作用域范围中,add_3(7)可以正常执行且返回值为10,之所以返回10是因为在my_add局部作用域中,变量n的值在闭包的作用下使得它在全局作用域也可以被访问到。
换成常规函数也可以实现闭包,只不过这种方式稍显啰嗦。

>>> def my_add(n):
        def wrapper(x):
            return x + n
        return wrapper
>>> add_2 = my_add(5)
>>> add_5(2)
7

那么是不是任何情况lambda函数都要比常规函数更清晰明了呢?看这个例子

f = lambda x: [[y for j, y in enumerate(set(x)) if (i >> j) & 1] for i in range(2 ** len(set(x)))]

这是返回某个集合所有自己的lamnda函数,非常难懂,zen of python中有这样一句话,‘Explicit is better than implicit(明了胜于晦涩)‘。记住,如果用lambda函数不能使你的代码变得更清晰,这时你就要考虑使用常规的方法来定义函数。

Python作为一门脚本语言,也具有一些函数式编程的思想,主要体现在下面几个方面:

  • Python的一些语法,比如lambda、列表解析、字典解析、生成器、iter等
  • Python的一些内置函数,包括map、reduce、filter、all、any、enumerate、zip等
  • Python的一些内置模块,比如itertools、functools和operator模块等
  • Python的一些第三方库,比如fn.py,toolz等

Python函数式编程之语法篇

(1) 列表解析,将range(5)的每个元素进行平方:

>>> a_list = [item ** 2 for item in range(5)]
>>> print(a_list)  
[0, 1, 4, 9, 16]

(2) 字典解析,将range(5)的每一个元素进行平方并作为value,key为一个指示:

>>> a_dict = {"%d^2"  % item: item ** 2 for item in range(5)}
>>> print(a_dict)
{'0^2': 0, '1^2': 1, '2^2': 4, '3^2': 9, '4^2': 16}

(3) 生成器:和列表解析比较类似,区别在于它的结果是generator object,不能直接打印,但可以进行迭代(使用next函数、放入for循环等)。

>>> a_generator = (item ** 2 for item in range(5))
>>> print(a_generator)
>>> print(next(a_generator))
0
>>> print(next(a_generator)) 
1

(4) iter函数和next函数:一个list类型不能使用next函数,需将其转化为iterator类型。

>>> a_list_generator = iter(a_list)
>>> print(next(a_list_generator))
0
>>> print(next(a_list_generator))
1
>>> print(type(a_list))
list
>>> print(type(a_list_generator))
list_iterator (列表迭代器)

(4) lambda表达式,即定义一些比较简单的匿名函数,lambda表达式和map、reduce、filter等函数混合使用威力巨大。例如求x的y次方:

>>> a_func = lambda x, y: x**y
>>> print(a_func(2, 3))
8

Python函数式编程之内置函数篇

(1) map函数:将一个函数应用于一个或多个可迭代对象(str,dict,list),返回一个map object。这里的函数可以为内置函数、operator模块中的函数或者一个lambda函数等。

>>> print(map(abs, range(-4,5)))  # 将内置函数abs应用于可迭代对象range(-4,5)
<map object at 0x10d678828>
>>> print(list(map(abs, range(-4, 5))))  # 将map object转化为list
[4, 3, 2, 1, 0, 1, 2, 3, 4]
>>> print(list(map(lambda x: x**2, range(5))))  # 将匿名函数lambda x: x**2 应用于可迭代对象range(5)
[0, 1, 4, 9, 16]
>>> print(list(map(lambda x,y: x**y, range(1,5), range(1,5))))  # 将匿名函数lambda x,y: x**y应用于两个可迭代对象range(1,5)和range(1,5),分别对应匿名函数的两个参数
[1, 4, 27, 256]

(2) reduce函数:这个函数并不能直接调用,而是需要通过functools库进行引入。该函数的作用是将一个可迭代对象中的元素进行reduce(累加等),最后一个参数可选,为初始值

>>> from functools import reduce
>>> print(reduce(lambda x,y: x+y, range(10)))  # 将可迭代对象range(10)中的元素进行累加
45
>>> print(reduce(lambda x,y: x+y, range(10), 100))  # 将可迭代对象range(10)中的元素进行累加,设置初始值为100
145
>>> print(reduce(lambda x,y: x+y, [[1, 2], [3, 4], [0]]))
[1, 2, 3, 4, 0]

(3) filter函数:按照字面意思理解即可,即过滤一个可迭代对象,保留为True的元素。

>>> print(filter(None, range(-4, 5)))
<filter object at 0x10d541710>
>>> print(list(filter(None, range(-4, 5))))  # 过滤掉为None的元素,0为None
[-4, -3, -2, -1, 1, 2, 3, 4]
>>> print(list(filter(lambda x:x>0, range(-4,5))))  # 过滤出大于0的元素
[1, 2, 3, 4]

(4) all、any函数:比较简单,还是可以按照字面意思理解,即判定一个可迭代对象是否全为True或这有部分为True

>>> print(all([0,1,2]))
False
>>> print(any([0,1,2]))
True

(5) enumerate函数,如果你想迭代一个列表或者元组,又想知道当前迭代元素的index值,那么enumerate就能满足你的需求

>>> for index, item in enumerate([1,2,3,4,5]):
        print("{0}: {1}".format(index, item))
0: 1
1: 2
2: 3
3: 4
4: 5

(6) zip函数,映射两个或多个可迭代对象,组成新的可迭代对象


>>> for a, b in zip([1,2,3],['a','b','c'])
        print(a,b)
1 a
2 b
3 c
>>> a_dict = dict(zip([1,2,3],['a','b','c']))
>>> print(a_dict)
{1: 'a', 2: 'b', 3: 'c'}

参考资料:
Python进阶:函数式编程实例(附代码)
什么时候使用lambda函数?

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值