Python三大高阶特性详解:装饰器、生成器与上下文管理器

文章目录

前言

掌握Python高阶特性,是告别"脚本小子"、迈向优雅编程的关键一步。本文将带你深入三个核心利器------装饰器、生成器与上下文管理器,从原理到实践,揭开Pythonic代码的神秘面纱。

一、装饰器

1.1什么是装饰器

装饰器是一种特殊的函数。它的作用是修改其他函数的行为。你可以在不改动原函数代码的情况下,给函数增加新功能。

这就像给手机套一个壳。手机本身没有变,但多了保护功能。

装饰器的优势:

  • 不修改原始函数的代码,就能增强功能
  • 代码更模块化,便于复用

1.2装饰器的执行原理

装饰器的本质是一个高阶函数。高阶函数就是接收函数作为参数,或则返回函数的函数。
最简单的装饰器:

python 复制代码
# 定义一个装饰器
def my_decorator(func):
    # 内部函数包裹原函数
    def wrapper():
        print("函数执行之前")
        func()  # 调用原函数
        print("函数执行之后")
    return wrapper

# 使用装饰器
@my_decorator
def say_hello():
    print("你好")

say_hello()

运行结果:

plain 复制代码
函数执行之前
你好
函数执行之后

代码详解:

  • my_decorator接收一个函数func作为参数
  • wrapper是内部函数,它在原函数前后添加了新逻辑
  • @my_decorator是语法糖,等价于say_hello = my_decorator(say_hello)
  • 调用say_hello()时,实际执行的是wrapper()

带参数的装饰器:

python 复制代码
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("函数执行之前")
        result = func(*args, **kwargs)  # 传递参数给原函数
        print("函数执行之后")
        return result
    return wrapper

@my_decorator
def add(a, b):
    return a + b

result = add(1, 2)
print(result)
plain 复制代码
函数执行之前
函数执行之后
3

代码详解:

  • *args接收所有位置参数,**kwargs接收所有关键字参数
  • 这样装饰器就能包裹任何参数的函数

1.3装饰器参数

有时候装饰器本身也需要参数。比如你想要控制是否打印日志。
带参数的装饰器需要三层嵌套:

python 复制代码
def log_decorator(enabled=True):
    # 第一层接收装饰器参数
    def decorator(func):
        # 第二层接收被装饰的函数
        def wrapper(*args, **kwargs):
            # 第三层是实际的包裹逻辑
            if enabled:
                print(f"正在调用函数: {func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

# 使用带参数的装饰器
@log_decorator(enabled=True)
def greet(name):
    print(f"你好, {name}")

greet("张三")
plain 复制代码
正在调用函数: greet
你好, 张三

代码详解:

  • 第一层log_decorator接收装饰器自己的参数
  • 第二层decorator接收被装饰的函数
  • 第三层wrapper执行实际的包裹逻辑

1.4装饰器的返回值

装饰器可以修改原函数的返回值。

python 复制代码
def double_result(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result * 2  # 返回值翻倍
    return wrapper

@double_result
def get_number():
    return 5

print(get_number())  # 输出10

实际应用场景:计算函数执行时间

python 复制代码
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"函数{func.__name__}执行了{end - start:.4f}秒")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    return "完成"

slow_function()

二、迭代器与生成器

2.1什么是迭代器

迭代器是一种对象。它可以让你逐个访问集合中的元素,而不需要一次性把所有的元素都加载到内存里。

你可以把迭代器理解为一个水龙头。水一滴一滴流出来,而不是一桶水直接倒出来。

2.2迭代器的原理

迭代器对象必须实现两个方法:

  • __iter__():返回迭代器对象本身
  • __next__():返回下一个元素,没有元素时抛出StopIteration异常
python 复制代码
class MyIterator:
    def __init__(self, max_num):
        self.max_num = max_num
        self.current = 0
    
    def __iter__(self):
        # 返回迭代器对象本身
        return self
    
    def __next__(self):
        # 返回下一个元素
        if self.current < self.max_num:
            num = self.current
            self.current += 1
            return num
        else:
            # 没有元素了,抛出异常
            raise StopIteration

# 使用迭代器
my_iter = MyIterator(5)
for num in my_iter:
    print(num)
    
plain 复制代码
0
1
2
3
4

代码详解:

  • __init__初始化迭代器,设置最大值和当前值
  • __iter__返回自身,让迭代器可以被for循环使用
  • __next__每次调用返回下一个值,直到没有值可返回

2.3什么是生成器

生成器是一种特殊的迭代器。它用函数来定义,而不是类。

生成器函数使用yield关键字。当执行到yield时,函数会暂停,并返回一个值。下次调用时,函数从暂停的地方继续执行。

2.4生成器的原理

python 复制代码
def my_generator():
    print("开始执行")
    yield 1  # 暂停,返回1
    print("继续执行")
    yield 2  # 暂停,返回2
    print("再次继续")
    yield 3  # 暂停,返回3
    print("执行结束")

# 使用生成器
gen = my_generator()

# 手动获取下一个值
print(next(gen))  # 输出1
print(next(gen))  # 输出2
print(next(gen))  # 输出3
# next(gen) 再次调用会抛出StopIteration
plain 复制代码
开始执行
1
继续执行
2
再次继续
3

代码详解:

  • 调用my_generator()不会执行函数体,而是返回一个生成器对象
  • next()触发函数执行,直到遇到yield
  • 每次yield后函数暂停,状态被保存
  • 下次next()从暂停处继续执行

用for循环遍历生成器:

python 复制代码
def count_up_to(max_num):
    count = 1
    while count <= max_num:
        yield count
        count += 1

# 使用生成器
for num in count_up_to(5):
    print(num)
    

生成器表达式:

python 复制代码
# 列表推导式,一次性生成所有元素
my_list = [x * 2 for x in range(5)]
print(my_list)  # [0, 2, 4, 6, 8]

# 生成器表达式,按需生成元素
my_gen = (x * 2 for x in range(5))
print(next(my_gen))  # 0
print(next(my_gen))  # 2

2.5生成器与迭代器的区别

对比项 迭代器 生成器
定义方式 用类定义,需要写__iter____next__ 用函数定义,使用yield
代码量 较多 较少,更简洁
状态保存 手动管理 自动保存,由Python处理
内存占用 取决于实现 惰性计算,占用小

三、上下文管理器

3.1什么是上下文管理器

上下文管理器用于管理资源的生命周期。它确保资源在使用前正确打开,在使用后正确关闭。

最常见的例子是文件操作。打开文件后,必须关闭文件。上下文管理器可以自动帮你关闭。

基本用法:

python 复制代码
# 不使用上下文管理器
file = open("test.txt", "w")
file.write("你好")
file.close()  # 容易忘记关闭

# 使用上下文管理器
with open("test.txt", "w") as file:
    file.write("你好")
# 退出with块时,文件自动关闭

3.2是哪个下文管理器的应用场景

场景一:文件操作

python 复制代码
# 读取文件
with open("data.txt", "r") as file:
    content = file.read()
    print(content)
# 文件自动关闭,即使发生异常也会关闭

# 同时操作多个文件
with open("source.txt", "r") as source, open("target.txt", "w") as target:
    target.write(source.read())
    

场景二:数据库连接

python 复制代码
import sqlite3

# 使用上下文管理器管理数据库连接
with sqlite3.connect("mydb.db") as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    results = cursor.fetchall()
    print(results)
# 连接自动关闭

场景三:自定义上下文管理器

可以用类来实现自定义的上下文管理器。需要实现__enter____exit__两个方法。

py 复制代码
class MyContext:
    def __enter__(self):
        # 进入上下文时执行
        print("进入上下文")
        return self  # 返回的对象会赋值给as后面的变量
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        # 退出上下文时执行
        # exc_type: 异常类型
        # exc_val: 异常值
        # exc_tb: 异常追踪信息
        print("退出上下文")
        return True  # 返回True表示异常已被处理

# 使用自定义上下文管理器
with MyContext() as ctx:
    print("执行中")
    

运行结果:

plain 复制代码
进入上下文
执行中
退出上下文

结语

装饰器让功能扩展如行云流水,生成器让内存效率化繁为简,上下文管理器让资源管控稳若磐石。三者皆是Python"简洁即美"哲学的最佳诠释。善用它们,你写出的将不再是能运行的代码,而是值得品味的工程艺术。

相关推荐
耿雨飞5 天前
Python 后端开发技术博客专栏 | 第 02 篇 函数式编程与 Python 魔法 -- 闭包、装饰器、高阶函数
开发语言·python·装饰器·高阶函数·闭包
高心星2 个月前
HarmonyOS 6.0应用开发——V2装饰器@param的使用
装饰器·param·鸿蒙6.0·harmonyos6.0·v2装饰器
雪碧聊技术2 个月前
生成器是什么?有什么用?
python·生成器·yield
高心星3 个月前
鸿蒙6.0应用开发——V2装饰器@Monitor的使用
装饰器·monitor·鸿蒙6.0·harmonyos6.0·v2装饰器
海棠AI实验室3 个月前
第十六章 迭代器与生成器:处理大数据的第一步
大数据·迭代器·生成器
高心星3 个月前
鸿蒙6.0应用开发——V2装饰器@ObservedV2和@Trace的使用
装饰器·observed·鸿蒙6.0·harmonyos6.0·v2装饰器
高心星3 个月前
HarmonyOS 6.0应用开发——V2装饰器@local的使用
装饰器·local·v2·鸿蒙6.0·harmonyos6.0·v2装饰器
qq_317620314 个月前
第06章-文件操作与异常处理
异常处理·文件读写·上下文管理器·数据序列化·pathlib模块
玄同7654 个月前
Python 装饰器:LLM API 的安全与可观测性增强
开发语言·人工智能·python·安全·自然语言处理·numpy·装饰器