Python 函数式编程 教学笔记
函数式编程: 在 Python 中,函数式编程强调使用函数和表达式 来进行数据处理,避免显式的循环和临时变量。常用的函数式编程工具包括高阶函数(如 map()
、filter()
)和**推导式 **(列表、集合、字典推导式)等。它们可以让代码更简洁明了,提高可读性和开发效率。
lambda
表达式用于创建匿名函数 ,其语法为 lambda 参数: 表达式
,会返回一个函数对象。它通常用于临时定义简单的函数。示例如下
1 2 3 4 5 6 7 8 9 10 11 12 def add (x, y ): return x + y print (add(3 , 5 )) f = lambda x, y: x + y print (f(3 , 5 )) print ((lambda x, y: x * y)(3 , 5 ))
注意:
lambda
表达式只能包含一个表达式,不能写赋值语句或多行逻辑。如果函数逻辑较复杂,仍然建议使用 def
定义函数。
map(function, iterable)
接收一个函数 (可接受匿名函数)和一个可迭代对象,将函数依次作用到每个元素上,返回一个迭代器 。
例如,计算列表中每个数的平方:
1 2 3 4 5 6 7 8 nums = [1 , 2 , 3 , 4 , 5 ] def square (x ): return x * x result = map (square, nums) print (list (result))
注意:在 Python 3 中,map()
返回的是一个迭代器,需要用 list()
、tuple()
转换为列表才能查看所有结果。我们也可以使用 lambda
表达式简化函数定义:
1 2 3 4 5 6 7 8 9 nums = [1 , 2 , 3 , 4 , 5 ] squares = list (map (lambda x: x * x, nums)) print (squares) nums1 = [1 , 2 , 3 , 4 , nums] doubles = list (map (lambda x: x * 2 , nums1)) print (doubles)
输出
1 2 [1, 4, 9, 16, 25] [2, 4, 6, 8, [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]]
如果有多个可迭代对象传入,map()
会并行取各可迭代对象的元素作为参数传给函数,直到最短的可迭代对象耗尽。
示例 1:基础并行计算
1 2 3 4 5 6 7 nums1 = [1 , 2 , 3 ] nums2 = [10 , 20 , 30 ] nums3 = [100 , 200 , 300 ] result = map (lambda x, y, z: x + y + z, nums1, nums2, nums3) print (list (result))
示例 2:不等长序列处理
1 2 3 4 5 6 letters = ['a' , 'b' , 'c' ] numbers = [1 , 2 ] combined = map (lambda l, n: f"{l} {n} " , letters, numbers) print (list (combined))
示例 3:类型混合操作
1 2 3 4 5 6 7 8 names = ["Alice" , "Bob" ] ages = [25 , 30 ] templates = ["{} is {} years old" , "Name: {}, Age: {}" ] formatted = map (lambda n, a, t: t.format (n, a), names, ages, templates) print (list (formatted))
示例 4:模拟内置函数 zip()
1 2 3 4 5 6 keys = ['name' , 'age' ] values = ['Alice' , 25 ] dict_pairs = map (lambda k, v: (k, v), keys, values) print (dict (dict_pairs))
filter(function, iterable)
用于过滤序列。
它也接收一个函数和一个可迭代对象,将函数作用到每个元素,保留返回值为 True
的元素.
返回一个迭代器。
例如,从列表中过滤出偶数:
1 2 3 4 5 nums = [1 , 2 , 3 , 4 , 5 , 6 ] evens = filter (lambda x: x % 2 == 0 , nums) print (list (evens))
同样地,在 Python 3 中,filter()
返回迭代器,需要 list()
转换为列表。若 function
为 None
,filter()
则会去掉序列中所有值为假(如 None
, 0
, ''
等)的元素。例如:
1 2 3 4 data = ["Alice" , "" , "Bob" , None , "Charlie" , "" ] cleaned = list (filter (None , data)) print (cleaned)
三元表达式(Ternary Operator) Python 的三元表达式(也称为条件表达式 )提供了一种简洁的方式来根据条件选择两个值中的一个。它的基本语法如下:
基本语法 1 value_if_true if condition else value_if_false
执行逻辑 :
如果 condition
为 True
,返回 value_if_true
。
如果 condition
为 False
,返回 value_if_false
。
示例 1:基本用法 1 2 3 4 5 6 x = 10 y = 20 max_value = x if x > y else y print (max_value)
示例 2:在赋值中使用 1 2 3 age = 18 status = "成年" if age >= 18 else "未成年" print (status)
示例 3:与函数返回值结合 1 2 3 4 5 def is_even (num ): return True if num % 2 == 0 else False print (is_even(4 )) print (is_even(5 ))
示例 4:嵌套三元表达式(不推荐,可读性差) 1 2 3 4 5 6 7 x = 10 y = 20 z = 30 result = "x最大" if x > y and x > z else ("y最大" if y > z else "z最大" ) print (result)
注意 :嵌套三元表达式会降低代码可读性,建议改用 if-elif-else
结构。
示例 5:在列表推导式中使用 1 2 3 4 numbers = [1 , 2 , 3 , 4 , 5 ] processed = [x * 2 if x % 2 == 0 else x for x in numbers] print (processed)
示例 6:在Lambda匿名函数中使用 1 is_positive = lambda x: True if x > 0 else False
三元表达式 vs 普通 if-else
场景
三元表达式
普通 if-else
简单条件赋值
value = a if cond else b
if cond: value = a else: value = b
多分支条件
可嵌套(但不推荐)
使用 elif
更清晰
代码简洁性
更紧凑
更冗长
可读性
简单条件时更直观
复杂逻辑时更易读
推导式(列表/集合/字典推导式) 推导式是一种简洁生成集合类型数据的表达式。常见的有列表推导式、集合推导式和字典推导式。
列表推导式 列表推导式(list comprehension)的基本形式如下,它可以生成一个新列表:
1 [表达式 for 变量 in 可迭代对象 if 条件]
示例 1 2 3 4 5 6 7 8 nums = [1 , 2 , 3 , 4 , 5 ] squares = [x * x for x in nums] print (squares) even_squares = [x * x for x in nums if x % 2 == 0 ] print (even_squares)
上面两个例子分别对应对每个元素操作和带条件的操作。
列表推导式可以包含多个 for
子句 ,从而实现嵌套循环。
例如,将二维列表拍平:
1 2 3 matrix = [[1 , 2 , 3 ], [4 , 5 , 6 ], [7 , 8 , 9 ]] flatten = [num for row in matrix for num in row] print (flatten)
小结: 官方教程指出,使用列表推导式可以在一行内创建列表,代码更加简洁易读。
集合推导式 集合推导式和列表推导式类似,使用 {}
来生成集合(去重且无序):
1 2 3 nums = [1 , 2 , 2 , 3 , 3 , 4 ] unique_set = {x for x in nums} print (unique_set)
如果需要按照顺序去重,可以先使用集合去除重复元素,然后转换为列表。不过要注意,set
会改变元素顺序。如果要保持原顺序去重,可使用字典(见后文)或循环处理。
字典推导式 字典推导式使用 {键: 值 for ...}
形式来生成字典。例如,将列表生成数字平方的字典:
1 2 3 nums = range (5 ) square_dict = {x: x * x for x in nums} print (square_dict)
也可以结合条件或解包键值对。例如,将一组键值元组转换为字典,只包含值大于 1 的项:
1 2 3 pairs = [('a' , 0 ), ('b' , 2 ), ('c' , 3 )] filtered_dict = {k: v for (k, v) in pairs if v > 1 } print (filtered_dict)
推导式使用语法简单,且不需要手动创建并填充新集合,从而减少样板代码。
实战案例:函数式编程在实际中与传统写法的对比 下面通过多个小案例展示函数式编程在日常任务中的实际效果与优势。
案例一:数据清洗 —— 去除空白与空值 目标 :从原始字符串列表中去除首尾空白并删除空项(包括 None
和空字符串)。
传统写法 :
1 2 3 4 5 6 7 8 9 raw = [" Alice " , "Bob" , " " , "Charlie " , "" , None , " David" ] cleaned = [] for s in raw: if s: stripped = s.strip() if stripped: cleaned.append(stripped) print (cleaned)
函数式写法 (推荐使用列表推导式):
1 2 3 cleaned = [s.strip() for s in raw if s and s.strip()] print (cleaned)
也可使用 filter()
和 map()
,但列表推导式更简洁直观。
案例二:文本处理 —— 拆分句子并统计单词数 目标 :将句子拆分为单词并统计每句单词数量。
传统写法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sentences = ["Hello world" , "Python is great" , " Functional Programming" ] words_list = [] word_counts = [] for s in sentences: s = s.strip() if not s: continue words = s.split() words_list.append(words) word_counts.append(len (words)) print (words_list) print (word_counts)
函数式写法 1 (列表推导式):
1 2 words_list = [s.strip().split() for s in sentences if s.strip()] word_counts = [len (words) for words in words_list]
函数式写法 2 (map()
+ filter()
):
1 2 3 sentence_stripped = filter (None , map (str .strip, sentences)) word_counts = list (map (lambda s: len (s.split()), sentence_stripped)) print (word_counts)
案例三:列表去重 —— 保留顺序或使用集合 目标 :去除重复元素,尽可能保留原顺序。
传统写法 :
1 2 3 4 5 6 nums = [3 , 1 , 2 , 3 , 2 , 4 , 1 ] unique = [] for x in nums: if x not in unique: unique.append(x) print (unique)
函数式写法 :
这些对比示例表明,函数式写法往往可以用更少的代码行实现相同功能,并且结构清晰,一眼就能看出“对每个元素做什么操作”。
函数式编程常见技巧进阶
一、高阶函数:map、filter、sorted 等组合使用 1 2 3 4 5 6 7 8 9 10 nums = [1 , 2 , 3 ] squared = list (map (lambda x: x**2 , nums)) evens = list (filter (lambda x: x % 2 == 0 , nums)) pairs = [(1 , 'Z' ), (3 , 'A' ), (2 , 'B' )] sorted_pairs = sorted (pairs, key=lambda x: x[1 ])
二、列表与字典操作的函数式写法 1 2 3 4 5 6 7 names = ["Alice" , "Bob" , "Charlie" ] upper_names = [(lambda s: s.upper())(name) for name in names] data = {'a' : 1 , 'b' : 2 } transformed = {k: (lambda v: v * 10 )(v) for k, v in data.items()}
三、闭包与延迟计算 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def power_maker (n ): return lambda x: x ** n square = power_maker(2 ) cube = power_maker(3 ) print (square(4 )) print (cube(3 )) button_actions = { "add" : lambda : print ("执行加法" ), "exit" : lambda : print ("退出程序" ) } button_actions["add" ]()
四、条件逻辑的函数式写法 1 2 3 4 5 6 7 8 9 10 11 grade = lambda score: "及格" if score >= 60 else "不及格" print (grade(75 )) category = lambda age: ( "儿童" if age < 12 else "青少年" if age < 18 else "成人" ) print (category(15 ))
五、特殊参数与函数定义技巧 1 2 3 4 5 6 7 8 adder = lambda x, y=10 : x + y print (adder(5 )) print (adder(5 , 20 )) processor = lambda *args, **kwargs: f"收到位置参数: {args} , 关键字参数: {kwargs} " print (processor(1 , 2 , a=3 ))
何时使用 lambda
场景
推荐使用
不推荐使用
简单数学运算
✅ map(lambda x: x*2, lst)
❌ 复杂公式
临时回调函数
✅ button.click(lambda: ...)
❌ 多步骤业务逻辑
排序/过滤键
✅ sorted(data, key=lambda x: x[1])
❌ 需要描述性名称时
函数参数简化
✅ functools.reduce(lambda a,b: a+b, lst)
❌ 需要类型提示时
函数式编程的例题
示例 1:从列表中提取偶数并平方 1 2 3 nums = [1 , 2 , 3 , 4 , 5 , 6 ] result = list (map (lambda x: x**2 , filter (lambda x: x % 2 == 0 , nums))) print (result)
示例 2:提取字符串中以“a”开头的单词 1 2 3 text = "apple banana apricot cherry avocado" result = list (filter (lambda w: w.startswith("a" ), text.split())) print (result)
示例 3:字典键值批量转换(键大写,值乘以10) 1 2 3 data = {"x" : 1 , "y" : 2 } result = {k.upper(): v * 10 for k, v in data.items()} print (result)
示例 4:字符串列表转为单词列表(去空白+小写) 1 2 3 lines = [" Hello World " , " PYTHON IS Fun " ] words = [word.lower() for line in lines for word in line.strip().split()] print (words)
示例 5:生成指定幂函数的列表(闭包) 1 2 3 4 5 def power_makers (n_list ): return [lambda x, n=n: x**n for n in n_list] powers = power_makers([1 , 2 , 3 ]) print ([f(2 ) for f in powers])
示例 6:对字符串按长度排序(忽略空白) 1 2 3 words = [" banana" , "apple" , " cherry " ] result = sorted (words, key=lambda s: len (s.strip())) print (result)
示例 7:从嵌套列表中提取所有数字 1 2 3 nested = [[1 , 2 ], [3 , 4 ], [5 ]] flat = [x for sublist in nested for x in sublist] print (flat)
示例 8:组合两个列表成字典(忽略 None 值) 1 2 3 4 keys = ["a" , "b" , "c" ] values = [1 , None , 3 ] result = {k: v for k, v in zip (keys, values) if v is not None } print (result)
示例 9:延迟计算表达式序列(惰性生成器) 1 2 3 expressions = [lambda x=i: x**2 for i in range (5 )] for f in expressions: print (f(), end=" " )
示例 10:多条件筛选数值 1 2 3 nums = range (20 ) filtered = list (filter (lambda x: x % 2 == 0 and x % 3 != 0 , nums)) print (filtered)
示例 11:提取唯一单词并按字母排序 1 2 3 text = "apple banana apple orange Banana" words = sorted (set (map (str .lower, text.split()))) print (words)
示例 12:统计每类词频(忽略大小写) 1 2 3 4 from collections import Countertext = "Dog cat dog CAT fish" counts = Counter(map (str .lower, text.split())) print (dict (counts))
示例 13:对二维矩阵按列求和 1 2 3 matrix = [[1 , 2 , 3 ], [4 , 5 , 6 ]] col_sum = list (map (sum , zip (*matrix))) print (col_sum)
示例 14:动态生成带标签的打印函数(闭包) 1 2 3 4 5 def labeler (tag ): return lambda msg: f"[{tag.upper()} ] {msg} " warn = labeler("warn" ) print (warn("Low battery" ))
示例 15:按条件映射标签(分级) 1 2 3 scores = [45 , 78 , 90 ] labels = list (map (lambda s: "优" if s >= 85 else "良" if s >= 60 else "差" , scores)) print (labels)
函数式编程的优势
减少样板代码: 使用 map
、filter
和推导式时,不需要先创建空列表再循环填充,省去了多行循环模板代码。
提高代码简洁度: 许多操作可以在一行表达式中完成,使得代码更简洁、一目了然。
加快开发速度: 由于代码量减少,开发、调试和维护都更高效。开发者能专注于“做什么”而非“如何做”。
可读性更强: 链式使用内置函数和推导式能够清楚表达数据转化逻辑,代码意图直观易懂。例如,一行推导式就可以展示过滤、映射、拆分等步骤。
易于组合和复用: 许多函数式工具产生迭代器,可以方便地与其他工具(如 itertools
)组合,编写复杂逻辑时保持简洁。
综上所述,掌握 map
、filter
、lambda
和各种推导式,可以帮助 Python 开发者编写更简洁、可读性更高的代码,大大减少样板工作,提高开发效率。