python:chapter12

第十二章:函数高级特性

完成本章学习后,你将能够:

  • 理解闭包和装饰器
  • 掌握函数柯里化和偏函数
  • 使用 functools 模块的工具
  • 理解生成器函数
  • 掌握上下文管理器

闭包是引用了外部变量的函数,即使外部函数已经执行完毕,闭包仍然可以访问这些变量。

def outer_function(x):
    def inner_function(y):
        return x + y  # inner引用了外部变量x
    return inner_function
 
# 创建闭包
add_10 = outer_function(10)
add_20 = outer_function(20)
 
print(add_10(5))   # 15
print(add_20(5))   # 25
 
# add_10和add_20各自保存了不同的x值
# 计数器
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(独立的计数器)
 
# 函数记忆化(简单版)
def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("函数执行前")
        result = func(*args, **kwargs)
        print("函数执行后")
        return result
    return wrapper
 
@my_decorator
def say_hello():
    print("Hello!")
 
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator
 
@repeat(times=3)
def greet(name):
    print(f"Hello, {name}!")
 
greet("Alice")
# 输出3次 Hello, Alice!
import time
from functools import wraps
 
# 计时装饰器
def timer(func):
    @wraps(func)  # 保留原函数元数据
    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
 
# 调试装饰器
def debug(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        args_repr = [repr(a) for a in args]
        kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
        signature = ", ".join(args_repr + kwargs_repr)
        print(f"调用 {func.__name__}({signature})")
        result = func(*args, **kwargs)
        print(f"{func.__name__} 返回 {result!r}")
        return result
    return wrapper
 
# 重试装饰器
def retry(max_attempts=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            attempts = 0
            while attempts < max_attempts:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    attempts += 1
                    if attempts == max_attempts:
                        raise
                    print(f"尝试 {attempts} 失败: {e},{delay}秒后重试...")
                    time.sleep(delay)
            return None
        return wrapper
    return decorator
from functools import partial
 
# 固定某些参数
basetwo = partial(int, base=2)
print(basetwo('10010'))  # 18
 
# 实际应用
import json
print_json = partial(json.dumps, indent=2, ensure_ascii=False)
data = {"name": "中文", "age": 25}
print(print_json(data))
from functools import reduce
 
# 累积计算
nums = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, nums)  # 120
 
# 带初始值
sum_with_initial = reduce(lambda x, y: x + y, nums, 10)  # 25
 
# 找最大值
maximum = reduce(lambda x, y: x if x > y else y, nums)
from functools import lru_cache
 
@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)
 
print(fibonacci(100))  # 瞬间完成
 
# 查看缓存信息
print(fibonacci.cache_info())
# CacheInfo(hits=98, misses=101, maxsize=128, currsize=101)
# 生成器函数使用yield代替return
def countdown(n):
    while n > 0:
        yield n
        n -= 1
 
# 使用
for num in countdown(5):
    print(num)  # 5, 4, 3, 2, 1
 
# 生成器表达式
gen = (x ** 2 for x in range(10))
print(sum(gen))  # 285
 
# yield from:委托给子生成器
def flatten(nested):
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item
 
print(list(flatten([1, [2, [3, 4]], 5])))  # [1, 2, 3, 4, 5]
# 使用with语句
with open("file.txt") as f:
    content = f.read()
 
# 自定义上下文管理器
class ManagedResource:
    def __enter__(self):
        print("资源获取")
        return self
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("资源释放")
        return False  # 不抑制异常
 
with ManagedResource() as resource:
    print("使用资源")
 
# 使用contextmanager装饰器
from contextlib import contextmanager
 
@contextmanager
def managed_file(filename):
    print(f"打开文件: {filename}")
    f = open(filename, 'w')
    try:
        yield f
    finally:
        f.close()
        print(f"关闭文件: {filename}")
 
with managed_file("test.txt") as f:
    f.write("Hello")

本章我们学习了:

  • 闭包的概念和应用
  • 装饰器的编写和使用
  • functools模块的工具
  • 生成器函数的高级用法
  • 上下文管理器

下一章:第十三章:面向对象编程基础

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • python/chapter12.txt
  • 最后更改: 2026/04/09 14:27
  • 张叶安