函数式编程基础
本节定位
这一节补充 Python 中更灵活的函数用法。lambda、map、filter、sorted 的 key 参数和装饰器会经常出现在数据处理、框架源码和工具函数中,目标是能读懂并适度使用,而不是一开始就追求复杂技巧。
学习目标
- 理解函数式编程的基本思想
- 掌握 lambda 匿名函数
- 熟练使用
map()、filter()、sorted()的 key 参数 - 理解闭包和装饰器的基本概念
什么是函数式编程?
简单来说,函数式编程就是把函数当作数据来传递和使用。
在 Python 中,函数是一等公民——它和数字、字符串一样,可以:
- 赋值给变量
- 作为参数传给另一个函数
- 作为返回值返回
# 函数可以赋值给变量
def greet(name):
return f"你好,{name}!"
say_hi = greet # 把函数赋值给变量(注意没有括号)
print(say_hi("小明")) # 你好,小明!
# 函数可以放进列表
def add(a, b): return a + b
def sub(a, b): return a - b
def mul(a, b): return a * b
operations = [add, sub, mul]
for op in operations:
print(op(10, 3)) # 13, 7, 30
Lambda 匿名函数
lambda 是一种一次性的小函数,不需要用 def 定义,也不需要名字。
基本语法
# 普通函数
def square(x):
return x ** 2
# 等价的 lambda
square = lambda x: x ** 2
print(square(5)) # 25
语法:lambda 参数: 表达式
# 一个参数
double = lambda x: x * 2
print(double(5)) # 10
# 多个参数
add = lambda a, b: a + b
print(add(3, 5)) # 8
# 带条件的
grade = lambda score: "及格" if score >= 60 else "不及格"
print(grade(75)) # 及格
print(grade(45)) # 不及格
lambda 的主要用途
lambda 最常见的用法是作为参数传给其他函数:
# 场景:按特定规则排序
students = [
{"name": "张三", "score": 85},
{"name": "李四", "score": 92},
{"name": "王五", "score": 78},
]
# 按成绩排序
students.sort(key=lambda s: s["score"])
print([s["name"] for s in students]) # ['王五', '张三', '李四']
# 按成绩降序
students.sort(key=lambda s: s["score"], reverse=True)
print([s["name"] for s in students]) # ['李四', '张三', '王五']
lambda 使用原则
- 简单逻辑用 lambda:
lambda x: x * 2 - 复杂逻辑用 def:如果 lambda 写出来很长、很难读,就应该用
def定义命名函数 - lambda 只能写一个表达式,不能写多行代码
map():对每个元素做同样的操作
map(函数, 可迭代对象) 对序列中的每个元素应用函数,返回新的序列。
# 把列表中的每个数字平方
numbers = [1, 2, 3, 4, 5]
# 方法 1:用 for 循环
squares = []
for n in numbers:
squares.append(n ** 2)
# 方法 2:用 map
squares = list(map(lambda x: x ** 2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# 方法 3:用列表推导式(通常更推荐)
squares = [x ** 2 for x in numbers]
print(squares) # [1, 4, 9, 16, 25]
map() 实际应用
# 批量转换数据类型
str_numbers = ["10", "20", "30", "40"]
numbers = list(map(int, str_numbers))
print(numbers) # [10, 20, 30, 40]
# 批量处理字符串
names = [" alice ", " BOB", "charlie "]
clean_names = list(map(str.strip, names))
print(clean_names) # ['alice', 'BOB', 'charlie']
# 使用已有函数
temperatures_c = [0, 20, 37, 100]
def c_to_f(c):
return c * 9/5 + 32
temperatures_f = list(map(c_to_f, temperatures_c))
print(temperatures_f) # [32.0, 68.0, 98.6, 212.0]
filter():筛选满足条件的元素
filter(函数, 可迭代对象) 保留函数返回 True 的元素。
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 筛选偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# 等价的列表推导式
evens = [x for x in numbers if x % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
filter() 实际应用
# 筛选及格的成绩
scores = [45, 78, 55, 92, 88, 30, 67, 100]
passed = list(filter(lambda s: s >= 60, scores))
print(f"及格的: {passed}") # [78, 92, 88, 67, 100]
# 筛选非空字符串
data = ["hello", "", "world", "", "python", ""]
non_empty = list(filter(None, data)) # filter(None, ...) 过滤掉假值
print(non_empty) # ['hello', 'world', 'python']
# 筛选特定类型的文件
files = ["data.csv", "model.py", "readme.md", "train.py", "config.json"]
py_files = list(filter(lambda f: f.endswith(".py"), files))
print(py_files) # ['model.py', 'train.py']
sorted() 的 key 参数
sorted() 的 key 参数让你自定义排序规则:
# 按绝对值排序
numbers = [-5, 3, -1, 4, -2]
result = sorted(numbers, key=abs)
print(result) # [-1, -2, 3, 4, -5]
# 按字符串长度排序
words = ["python", "AI", "deep", "learning"]
result = sorted(words, key=len)
print(result) # ['AI', 'deep', 'python', 'learning']
# 按字典的某个键排序
students = [
{"name": "张三", "age": 20, "score": 85},
{"name": "李四", "age": 22, "score": 92},
{"name": "王五", "age": 19, "score": 78},
]
# 按成绩排序
by_score = sorted(students, key=lambda s: s["score"], reverse=True)
for s in by_score:
print(f"{s['name']}: {s['score']}分")
# 李四: 92分
# 张三: 85分
# 王五: 78分
# 按多个条件排序(先按成绩降序,成绩相同按年龄升序)
students2 = [
{"name": "A", "age": 20, "score": 85},
{"name": "B", "age": 22, "score": 85},
{"name": "C", "age": 19, "score": 92},
]
result = sorted(students2, key=lambda s: (-s["score"], s["age"]))
for s in result:
print(f"{s['name']}: score={s['score']}, age={s['age']}")
# C: score=92, age=19
# A: score=85, age=20
# B: score=85, age=22
闭包(Closure)
闭包是一个函数,它记住了外层函数的变量,即使外层函数已经执行完毕。
def make_multiplier(factor):
"""创建一个乘法器"""
def multiplier(x):
return x * factor # factor 来自外层函数
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
print(double(10)) # 20
闭包的实际应用
# 创建计数器
def make_counter(start=0):
count = [start] # 用列表包装,以便在内层函 数中修改
def counter():
count[0] += 1
return count[0]
return counter
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
# 创建带前缀的日志函数
def make_logger(prefix):
def log(message):
from datetime import datetime
timestamp = datetime.now().strftime("%H:%M:%S")
print(f"[{prefix}] {timestamp} {message}")
return log
info = make_logger("INFO")
error = make_logger("ERROR")
info("程序启动") # [INFO] 14:30:01 程序启动
error("文件未找到") # [ERROR] 14:30:01 文件未找到