大家好,我是正在实战各种 AI 项目的程序员晚枫。

🎬 开篇:理解"函数是一等公民"

你有没有想过,为什么 Python 可以这样写?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 把函数当变量用
def greet(name):
return f"Hello, {name}"

say_hello = greet # 函数赋值给变量
print(say_hello("Alice")) # Hello, Alice

# 把函数存进列表
funcs = [len, str.upper, max]
print(funcs[0]("Hello")) # 5

# 把函数当参数传递
result = map(str.upper, ['hello', 'world'])
print(list(result)) # ['HELLO', 'WORLD']

这就是函数是一等公民(First-Class Citizen)的含义:函数可以像普通对象一样被操作。

一等公民的四个权利

在 Python 中,函数拥有以下"权利":

  1. 可以赋值给变量
  2. 可以作为参数传递
  3. 可以作为返回值
  4. 可以存储在数据结构中

今天我们就深入理解这个核心概念,掌握函数式编程的精髓。


🎯 函数作为对象

1. 函数赋值给变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def greet(name):
"""问候函数"""
return f"Hello, {name}"

# 函数本身是一个对象
print(type(greet)) # <class 'function'>

# 赋值给另一个变量
say_hello = greet

# 现在两个变量指向同一个函数对象
print(say_hello is greet) # True

# 调用
print(greet("Alice")) # Hello, Alice
print(say_hello("Bob")) # Hello, Bob

# 删除原变量,不影响新变量
del greet
print(say_hello("Charlie")) # Hello, Charlie

2. 函数存储在数据结构中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 函数列表
math_ops = [abs, max, min, sum, round]

for op in math_ops:
result = op([-1, 2, -3, 4])
print(f"{op.__name__}: {result}")

# 输出:
# abs: 4
# max: 4
# min: -3
# sum: 2
# round: [-1, 2, -3, 4]

# 函数字典:策略模式
def add(x, y):
return x + y

def subtract(x, y):
return x - y

def multiply(x, y):
return x * y

def divide(x, y):
return x / y if y != 0 else "Error"

operations = {
'+': add,
'-': subtract,
'*': multiply,
'/': divide,
}

# 计算器
def calculate(x, op, y):
func = operations.get(op)
if func:
return func(x, y)
return "未知操作"

print(calculate(10, '+', 5)) # 15
print(calculate(10, '*', 5)) # 50

3. 函数作为参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 高阶函数:接受函数作为参数
def apply_operation(data, operation):
"""对数据应用操作"""
return [operation(item) for item in data]

numbers = [1, 2, 3, 4, 5]

# 传入不同的函数
squared = apply_operation(numbers, lambda x: x ** 2)
cubed = apply_operation(numbers, lambda x: x ** 3)
negated = apply_operation(numbers, lambda x: -x)

print(squared) # [1, 4, 9, 16, 25]
print(cubed) # [1, 8, 27, 64, 125]
print(negated) # [-1, -2, -3, -4, -5]

# 实际应用:排序
students = [
{'name': 'Alice', 'age': 20, 'score': 95},
{'name': 'Bob', 'age': 19, 'score': 87},
{'name': 'Charlie', 'age': 21, 'score': 92},
]

# 按年龄排序
by_age = sorted(students, key=lambda s: s['age'])
print([s['name'] for s in by_age]) # ['Bob', 'Alice', 'Charlie']

# 按分数排序
by_score = sorted(students, key=lambda s: s['score'], reverse=True)
print([s['name'] for s in by_score]) # ['Alice', 'Charlie', 'Bob']

4. 函数作为返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 工厂函数:返回配置好的函数
def make_power(n):
"""创建求 n 次幂的函数"""
def power(x):
return x ** n
return power

# 创建不同的幂函数
square = make_power(2)
cube = make_power(3)
quartic = make_power(4)

print(square(3)) # 9
print(cube(3)) # 27
print(quartic(3)) # 81

# 实际应用:验证器工厂
def make_validator(min_val, max_val):
"""创建范围验证器"""
def validate(value):
return min_val <= value <= max_val
return validate

# 创建年龄验证器
is_valid_age = make_validator(0, 120)
print(is_valid_age(25)) # True
print(is_valid_age(150)) # False

# 创建分数验证器
is_valid_score = make_validator(0, 100)
print(is_valid_score(95)) # True
print(is_valid_score(105)) # False

🔒 闭包:函数记住它的环境

什么是闭包?

闭包(Closure)是一个函数,它"记住"了定义时的环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def make_multiplier(n):
"""创建乘法器"""
def multiplier(x):
return x * n # multiplier 记住了 n 的值
return multiplier

# 创建不同的乘法器
double = make_multiplier(2)
triple = make_multiplier(3)
quadruple = make_multiplier(4)

print(double(5)) # 10
print(triple(5)) # 15
print(quadruple(5)) # 20

关键点

  • multiplier 函数"闭包"了外部变量 n
  • 即使 make_multiplier 已经执行完毕,n 依然被记住
  • 每个 multiplier 实例都有自己的 n

闭包的三个要素

1
2
3
4
5
6
7
def outer(x):           # 1. 外部函数
def inner(y): # 2. 内部函数
return x + y # 3. 引用外部变量
return inner

add_5 = outer(5)
print(add_5(10)) # 15

查看 closure 变量

1
2
3
4
5
6
7
8
9
10
11
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier

double = make_multiplier(2)

# 查看闭包变量
print(double.__code__.co_freevars) # ('n',) - 自由变量
print(double.__closure__) # 包含 n 的值
print(double.__closure__[0].cell_contents) # 2

闭包的实际应用

1. 配置函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def make_url_formatter(base_url, api_key):
"""创建 API URL 格式化器"""
def format_url(endpoint, **params):
url = f"{base_url}/{endpoint}?key={api_key}"
for key, value in params.items():
url += f"&{key}={value}"
return url
return format_url

# 创建不同 API 的格式化器
github = make_url_formatter("https://api.github.com", "gh_xxx")
weather = make_url_formatter("https://api.weather.com", "wth_xxx")

print(github("users", name="alice"))
# https://api.github.com/users?key=gh_xxx&name=alice

print(weather("forecast", city="beijing"))
# https://api.weather.com/forecast?key=wth_xxx&city=beijing

2. 缓存/记忆化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def memoize(func):
"""记忆化装饰器"""
cache = {}

def wrapper(*args):
if args in cache:
print(f"缓存命中: {args}")
return cache[args]
result = func(*args)
cache[args] = result
return result

return wrapper

@memoize
def fibonacci(n):
"""斐波那契数列"""
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10)) # 第一次计算
print(fibonacci(10)) # 缓存命中

3. 回调函数

1
2
3
4
5
6
7
8
9
10
11
12
def make_callback(prefix):
"""创建带前缀的回调函数"""
def callback(message):
print(f"[{prefix}] {message}")
return callback

# 创建不同的回调
info_callback = make_callback("INFO")
error_callback = make_callback("ERROR")

info_callback("服务启动")
error_callback("连接失败")

🧩 高阶函数

内置高阶函数

map:映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# map(func, iterable) - 对每个元素应用函数
numbers = [1, 2, 3, 4, 5]

# 平方
squared = map(lambda x: x ** 2, numbers)
print(list(squared)) # [1, 4, 9, 16, 25]

# 转字符串
str_numbers = map(str, numbers)
print(list(str_numbers)) # ['1', '2', '3', '4', '5']

# 多个序列
a = [1, 2, 3]
b = [10, 20, 30]
sums = map(lambda x, y: x + y, a, b)
print(list(sums)) # [11, 22, 33]

# 等价于列表推导式
squared = [x ** 2 for x in numbers]

filter:过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# filter(func, iterable) - 保留满足条件的元素
numbers = range(10)

# 过滤偶数
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens)) # [0, 2, 4, 6, 8]

# 过滤非空字符串
texts = ['hello', '', 'world', None, 'python', '']
valid = filter(None, texts) # None 表示过滤假值
print(list(valid)) # ['hello', 'world', 'python']

# 等价于列表推导式
evens = [x for x in numbers if x % 2 == 0]

reduce:归约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from functools import reduce

# reduce(func, iterable, initial) - 累积计算
numbers = [1, 2, 3, 4, 5]

# 求和
total = reduce(lambda x, y: x + y, numbers)
print(total) # 15

# 求积
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120

# 找最大值
maximum = reduce(lambda x, y: x if x > y else y, numbers)
print(maximum) # 5

# 带初始值
total = reduce(lambda x, y: x + y, numbers, 100)
print(total) # 115

# 实际应用:多层嵌套
nested = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
flat = reduce(lambda x, y: x + y, reduce(lambda x, y: x + y, nested))
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8]

sorted、min、max 的 key 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# sorted 排序
words = ['banana', 'pie', 'Washington', 'book']

# 按字母顺序(不区分大小写)
sorted_words = sorted(words, key=str.lower)
print(sorted_words) # ['banana', 'book', 'pie', 'Washington']

# 按长度排序
by_length = sorted(words, key=len)
print(by_length) # ['pie', 'book', 'banana', 'Washington']

# 按长度降序
by_length_desc = sorted(words, key=len, reverse=True)
print(by_length_desc) # ['Washington', 'banana', 'book', 'pie']

# 复杂对象排序
students = [
{'name': 'Alice', 'score': 95},
{'name': 'Bob', 'score': 87},
{'name': 'Charlie', 'score': 92},
]

by_score = sorted(students, key=lambda s: s['score'], reverse=True)
print([s['name'] for s in by_score]) # ['Alice', 'Charlie', 'Bob']

# min 和 max
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(min(numbers)) # 1
print(max(numbers)) # 9

# 带 key
words = ['apple', 'pie', 'banana']
print(min(words, key=len)) # 'pie'
print(max(words, key=len)) # 'banana'

🎭 lambda 表达式

lambda 语法

1
2
3
4
5
6
7
# lambda 参数: 表达式
add = lambda x, y: x + y
print(add(3, 4)) # 7

# 等价于
def add(x, y):
return x + y

lambda 的使用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1. 排序
students = [('Alice', 95), ('Bob', 87), ('Charlie', 92)]
sorted_students = sorted(students, key=lambda s: s[1], reverse=True)
print(sorted_students) # [('Alice', 95), ('Charlie', 92), ('Bob', 87)]

# 2. 过滤
numbers = range(20)
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# 3. 映射
squares = list(map(lambda x: x ** 2, range(5)))
print(squares) # [0, 1, 4, 9, 16]

# 4. 字典值排序
d = {'a': 3, 'b': 1, 'c': 2}
sorted_items = sorted(d.items(), key=lambda item: item[1])
print(sorted_items) # [('b', 1), ('c', 2), ('a', 3)]

# 5. 回调函数
buttons = [
{'text': 'Save', 'action': lambda: print('保存')},
{'text': 'Cancel', 'action': lambda: print('取消')},
]
for button in buttons:
button['action']()

lambda 的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ❌ lambda 只能是单个表达式
# lambda x: print(x); return x # 语法错误

# ❌ 复杂逻辑应该用普通函数
# 难以阅读
result = map(lambda x: x ** 2 if x > 0 else 0, range(-5, 5))

# ✅ 更清晰
def square_if_positive(x):
if x > 0:
return x ** 2
return 0

result = map(square_if_positive, range(-5, 5))

📊 性能对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import timeit

# 列表推导式 vs map
numbers = list(range(10000))

list_comp = timeit.timeit('[x**2 for x in numbers]',
globals=globals(), number=1000)

map_func = timeit.timeit('list(map(lambda x: x**2, numbers))',
globals=globals(), number=1000)

print(f"列表推导式: {list_comp:.4f}s")
print(f"map+lambda: {map_func:.4f}s")
# 列表推导式通常更快

# 但用内置函数时,map 更快
upper_list = timeit.timeit('[s.upper() for s in strings]',
globals=globals(),
setup="strings = ['hello'] * 1000",
number=1000)

upper_map = timeit.timeit('list(map(str.upper, strings))',
globals=globals(),
setup="strings = ['hello'] * 1000",
number=1000)

print(f"列表推导式: {upper_list:.4f}s")
print(f"map: {upper_map:.4f}s")
# map 更快(因为用的是内置函数)

⚠️ 避坑指南

陷阱 1:闭包中的延迟绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ❌ 经典错误
def make_multipliers():
funcs = []
for i in range(5):
def multiplier(x):
return x * i # i 是延迟绑定的
funcs.append(multiplier)
return funcs

multipliers = make_multipliers()
print([m(10) for m in multipliers]) # [40, 40, 40, 40, 40] - 都是 4 * 10

# ✅ 正确:用默认参数捕获当前值
def make_multipliers_fixed():
funcs = []
for i in range(5):
def multiplier(x, n=i): # 默认参数立即求值
return x * n
funcs.append(multiplier)
return funcs

multipliers = make_multipliers_fixed()
print([m(10) for m in multipliers]) # [0, 10, 20, 30, 40]

陷阱 2:lambda 中的循环变量

1
2
3
4
5
6
7
# ❌ 错误
funcs = [lambda: i for i in range(5)]
print([f() for f in funcs]) # [4, 4, 4, 4, 4]

# ✅ 正确
funcs = [lambda i=i: i for i in range(5)]
print([f() for f in funcs]) # [0, 1, 2, 3, 4]

陷阱 3:修改闭包变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def counter():
count = 0
def inc():
count += 1 # UnboundLocalError!
return count
return inc

# ✅ 使用 nonlocal
def counter_fixed():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc

c = counter_fixed()
print(c()) # 1
print(c()) # 2
print(c()) # 3

🎯 本讲总结

通过本讲,我们掌握了:

知识点核心要点
函数是一等公民可赋值、存储、传递、返回
高阶函数map、filter、reduce、sorted
闭包函数记住定义时的环境变量
lambda匿名函数,用于简单场景
延迟绑定闭包中的常见陷阱,用默认参数解决
nonlocal在闭包中修改外部变量

记住这句话

函数是一等公民,这让 Python 支持函数式编程,能写出更灵活、更优雅的代码。


📚 推荐教材

《Python 编程从入门到实践(第 3 版)》 | 《流畅的 Python(第 2 版)》 | 《CPython 设计与实现》

学习路线: 零基础 → 《从入门到实践》 → 《流畅的 Python》 → 本门课程 → 《CPython 设计与实现》


🎓 加入《流畅的 Python》直播共读营

学到这里,如果你想系统吃透这本书——欢迎加入我的直播共读课。

  • 每周直播精讲,逐章拆解核心知识点
  • 专属学习群,随时答疑交流
  • 试运营特惠:499 元299 元

👉 【立即报名《流畅的 Python》共读课】https://mp.weixin.qq.com/s/ivHJwn1nNx5ug4TFrapvGg


🔗 课程导航

上一讲:文本与字节 | 下一讲:装饰器详解


💬 联系我

平台账号/链接
微信扫码加好友
微博@程序员晚枫
知乎@程序员晚枫
抖音@程序员晚枫
小红书@程序员晚枫
B 站Python 自动化办公社区

主营业务:AI 编程培训、企业内训、技术咨询

🎓 AI 编程实战课程

想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!

fluent-python.png