Skip to content

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 把函数变成生成器,支持惰性迭代。