主题
Python 函数、装饰器与作用域
本文深入 Python 函数的核心机制:参数传递、闭包、装饰器与作用域规则。
作者:yanshaodong
函数定义
python
def add(a, b):
return a + b
# 默认参数
def greet(name, greeting="Hello"):
return f"{greeting}, {name}"
# 返回值可多
def min_max(items):
return min(items), max(items)参数类型
python
# 位置 / 关键字
def f(a, b, c):
return a + b + c
f(1, 2, 3)
f(1, c=3, b=2)
# 可变位置参数 *args
def total(*args):
return sum(args)
# 可变关键字参数 **kwargs
def show(**kwargs):
for k, v in kwargs.items():
print(f"{k}={v}")
# 仅位置 / 仅关键字
def pos_only(a, b, /, c, *, d):
pass
# a,b 只能位置传;d 只能关键字传注意:默认参数应是不可变对象,避免可变默认值的共享陷阱。
python
# 错误示范
def bad(x=[]):
x.append(1)
return x
# 正确做法
def good(x=None):
x = x or []
x.append(1)
return x匿名函数 lambda
python
square = lambda x: x * x
nums = [5, 2, 9, 1]
nums.sort(key=lambda n: -n) # 降序
print(nums) # [9, 5, 2, 1]lambda 仅适合单行简单表达式,复杂逻辑请用普通函数。
作用域与闭包
Python 作用域遵循 LEGB 规则:Local → Enclosing → Global → Builtin。
python
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x)
inner()
outer() # local
print(x) # global闭包:内层函数捕获外层变量:
python
def make_counter():
count = 0
def counter():
nonlocal count # 声明修改外层变量
count += 1
return count
return counter
c = make_counter()
print(c(), c(), c()) # 1 2 3装饰器
装饰器是接收函数、返回新函数的高阶函数,用于横切逻辑(日志、计时、鉴权等)。
python
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {time.perf_counter() - start:.4f}s")
return result
return wrapper
@timer
def slow():
time.sleep(0.5)
slow()带参数的装饰器
python
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def hi():
print("hi")用 functools.wraps 保留元信息
python
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper生成器与 yield
python
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
print(list(fib(6))) # [0, 1, 1, 2, 3, 5]生成器惰性求值,适合处理大数据流,节省内存。
小结
*args/**kwargs分别收集位置与关键字参数。- 默认参数用不可变对象,避免共享状态。
- 闭包通过
nonlocal修改外层变量。 - 装饰器是高阶函数,配合
@wraps保留原函数元信息。 yield把函数变成生成器,支持惰性迭代。