Python 函数进阶
目录
学习目标
- 理解变量的作用域与 LEGB 规则
- 掌握
global和nonlocal关键字 - 学会使用 lambda 表达式
- 理解高阶函数与函数作为参数
一、变量作用域
1.1 局部变量与全局变量
# 全局变量
count = 0
def increment():
local_count = 1 # 局部变量,只在函数内有效
print(f"局部: {local_count}")
print(f"全局: {count}") # 可以读取全局变量
increment()
# 局部: 1
# 全局: 0
# print(local_count) # NameError: 局部变量在函数外不可访问1.2 修改全局变量
counter = 0
def increment_wrong():
# counter += 1 # UnboundLocalError! 不能这样修改全局变量
pass
def increment_correct():
global counter # 声明使用全局变量
counter += 1
print(f"counter = {counter}")
increment_correct() # counter = 1
increment_correct() # counter = 2
print(counter) # 2二、LEGB 规则
Python 查找变量时遵循 LEGB 顺序:
| 层级 | 英文 | 说明 |
|---|---|---|
| L | Local | 局部作用域(函数内部) |
| E | Enclosing | 嵌套函数的父函数作用域 |
| G | Global | 全局作用域(模块级别) |
| B | Built-in | 内置作用域(Python 内置函数和变量) |
x = "global" # G: 全局
def outer():
x = "enclosing" # E: 嵌套
def inner():
x = "local" # L: 局部
print(x) # 查找顺序: L → E → G → B
inner()
outer() # local
print(x) # global各层级示例
# 1. Local(局部)
def func():
local_var = "我在函数内"
print(local_var)
func()
# print(local_var) # NameError
# 2. Enclosing(嵌套)
def outer():
enclosing_var = "我在外层函数"
def inner():
print(enclosing_var) # 可以访问外层变量
inner()
outer() # 我在外层函数
# 3. Global(全局)
global_var = "我是全局变量"
def func():
print(global_var) # 可以读取
func() # 我是全局变量
# 4. Built-in(内置)
print(len("hello")) # len 是内置函数
print(max([1, 2, 3])) # max 是内置函数三、nonlocal 关键字
nonlocal 用于在嵌套函数中修改外层(非全局)变量。
def counter():
count = 0 # 外层函数的局部变量
def increment():
# count += 1 # UnboundLocalError!
nonlocal count # 声明使用外层变量
count += 1
return count
def decrement():
nonlocal count
count -= 1
return count
return increment, decrement
inc, dec = counter()
print(inc()) # 1
print(inc()) # 2
print(dec()) # 1
print(inc()) # 2global vs nonlocal 对比
x = "global"
def outer():
x = "enclosing"
def inner_global():
global x
x = "modified global"
def inner_nonlocal():
nonlocal x
x = "modified enclosing"
print(f"修改前: {x}") # enclosing
inner_nonlocal()
print(f"nonlocal 后: {x}") # modified enclosing
inner_global()
print(f"global 后: {x}") # modified enclosing(局部不变)
outer()
print(f"全局: {x}") # modified global四、lambda 表达式
lambda 是创建小型匿名函数的简洁方式。
基本语法
# 普通函数
def add(x, y):
return x + y
# 等价的 lambda
add_lambda = lambda x, y: x + y
print(add(3, 5)) # 8
print(add_lambda(3, 5)) # 8lambda 的使用场景
# 1. 作为排序的 key
students = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 92},
{"name": "Charlie", "score": 78},
]
# 按分数排序
students.sort(key=lambda s: s["score"], reverse=True)
print(students)
# [{'name': 'Bob', 'score': 92}, {'name': 'Alice', 'score': 85}, ...]
# 2. 配合 map()
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# 3. 配合 filter()
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4]
# 4. 配合 reduce()
from functools import reduce
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120lambda 的限制
# lambda 只能包含单个表达式,不能有多条语句
# 以下写法非法:
# f = lambda x: print(x); return x + 1
# 如果需要复杂逻辑,应该使用普通函数
def complex_func(x):
if x > 0:
return x * 2
else:
return x * 3五、高阶函数
高阶函数是指接收函数作为参数,或返回函数的函数。
5.1 函数作为参数
def apply_operation(numbers, operation):
"""接收一个函数作为参数"""
return [operation(n) for n in numbers]
nums = [1, 2, 3, 4, 5]
# 传递不同的函数
print(apply_operation(nums, lambda x: x ** 2)) # [1, 4, 9, 16, 25]
print(apply_operation(nums, lambda x: x * 2)) # [2, 4, 6, 8, 10]
print(apply_operation(nums, abs)) # [1, 2, 3, 4, 5]5.2 函数作为返回值
def make_multiplier(n):
"""返回一个函数"""
def multiplier(x):
return x * n
return multiplier
times3 = make_multiplier(3)
times5 = make_multiplier(5)
print(times3(10)) # 30
print(times5(10)) # 50
print(times3(times5(2))) # 305.3 内置高阶函数
numbers = [-3, -2, -1, 0, 1, 2, 3]
# map(): 对每个元素应用函数
absolute = list(map(abs, numbers))
print(absolute) # [3, 2, 1, 0, 1, 2, 3]
# filter(): 按条件筛选
positives = list(filter(lambda x: x > 0, numbers))
print(positives) # [1, 2, 3]
# sorted(): 排序(不修改原列表)
sorted_nums = sorted(numbers, key=lambda x: abs(x), reverse=True)
print(sorted_nums) # [-3, 3, -2, 2, -1, 1, 0]
# zip(): 并行迭代
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
print(f"{name}: {age}")
# enumerate(): 带索引迭代
for i, num in enumerate(numbers, start=1):
print(f"{i}: {num}")六、闭包(Closure)
闭包是指内部函数记住了外层函数的变量,即使外层函数已经执行完毕。
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
c1 = make_counter()
c2 = make_counter()
print(c1()) # 1
print(c1()) # 2
print(c2()) # 1(独立的计数器)
print(c1()) # 3闭包三要素:
- 嵌套函数
- 内部函数引用了外部变量
- 外部函数返回了内部函数
七、综合示例
"""
函数工厂:根据不同配置生成不同的处理函数
"""
def make_formatter(template):
"""
创建一个格式化函数
template: 包含 {value} 占位符的字符串
"""
def formatter(value):
return template.format(value=value)
return formatter
# 创建不同的格式化器
currency = make_formatter("${value:.2f}")
percentage = make_formatter("{value:.1%}")
hex_format = make_formatter("0x{value:x}")
print(currency(123.456)) # $123.46
print(percentage(0.85)) # 85.0%
print(hex_format(255)) # 0xff
# 装饰器风格的用法
def timing_decorator(func):
"""计时装饰器"""
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} 耗时: {elapsed:.4f} 秒")
return result
return wrapper
@timing_decorator
def slow_function():
import time
time.sleep(0.1)
return "done"
slow_function()小结
- 变量查找遵循 LEGB 规则:Local → Enclosing → Global → Built-in
global修改全局变量,nonlocal修改外层(非全局)变量lambda创建匿名函数,适合简单场景- 高阶函数接收或返回函数,
map()、filter()、sorted()是常用内置高阶函数 - 闭包让内部函数记住外层变量,实现数据封装
练习
- 分析以下代码的输出,并解释 LEGB 查找过程:
x = 10 def outer(): x = 20 def inner(): x = 30 print(x) inner() print(x) outer() print(x) - 使用
lambda和sorted()将列表按字符串长度排序。 - 编写一个函数
make_power(n),返回计算 x 的 n 次方的函数。 - 使用
nonlocal实现一个计数器,支持增加、减少和重置功能。 - 使用
map()和filter()从列表中筛选出所有正数的平方。