有参装饰器、迭代器、生成器和协程函数

Python装饰器、迭代器与生成器完整进阶笔记

一、Python装饰器

1.1 装饰器核心基础概念

装饰器本质是一个闭包函数,作用是在不修改原函数代码、不改变原函数调用方式的前提下,为函数新增额外功能,符合编程中的开闭原则:对扩展开放,对修改关闭。

装饰器分为无参装饰器和有参装饰器两类,无参装饰器仅能实现固定功能扩展,有参装饰器可通过传入参数实现动态定制化功能,适配更多业务场景。

1.2 无参装饰器

1.2.1 无参装饰器通用模板

无参装饰器结构固定,外层函数接收原函数作为参数,内层wrapper函数负责执行原函数、扩展新增逻辑,最终返回内层函数地址。

def deco(func):
    def wrapper(*args,**kwargs):
        # 函数执行前扩展逻辑
        res = func(*args,**kwargs)
        # 函数执行后扩展逻辑
        return res
    return wrapper

# 装饰器使用
@deco
def index():
    pass

1.2.2 多装饰器叠加执行逻辑

当多个装饰器同时装饰一个函数时,存在两个核心执行阶段,顺序完全不同,是装饰器的核心考点:

加载阶段(外层装饰器函数执行):自下而上执行,优先执行靠近原函数的装饰器外层逻辑

执行阶段(内层wrapper函数执行):自上而下执行,优先执行最外层装饰器的内层逻辑

加载阶段仅在代码加载时执行一次,执行阶段在调用原函数时触发执行。

def deco1(func1):
    print("deco1...")
    def wrapper1(*args, **kwargs):
        print('wrapper1...')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def deco2(func2):
    print("deco2...")
    def wrapper2(*args, **kwargs):
        print('wrapper2...')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def deco3(func3):
    print("deco3...")
    def wrapper3(*args, **kwargs):
        print('wrapper3...')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3

# 多装饰器叠加装饰
@deco1
@deco2
@deco3
def index():
    print('from index')
    return 123

# 调用函数触发执行阶段
res = index()
print(res)

对应输出结果:

加载阶段输出:deco3...、deco2...、deco1...

执行阶段输出:wrapper1...、wrapper2...、wrapper3...、from index、123

1.2.3 无参装饰器实战案例(固定逻辑权限校验)

实现固定文件模式的账号密码登录校验,为目标函数新增登录鉴权功能。

def auth(func):
    def wrapper(*args, **kwargs):
        username = input("username>>>: ").strip()
        password = input("password>>>: ").strip()

        if username == "egon" and password == "123":
            print("登录成功")
            res = func(*args, **kwargs)
            return res
        else:
            print("账号或密码错误")
    return wrapper

@auth
def index():
    print('from index ....')

index()

1.3 有参装饰器

1.3.1 有参装饰器通用模板

有参装饰器在无参装饰器基础上,外层嵌套一层函数用于接收自定义参数,实现装饰器逻辑动态化,参数可自定义传递,适配不同场景需求。

def outter(xxx):
    def deco(func):
        def wrapper(*args,**kwargs):
            # 可使用外层传递的参数xxx
            print(xxx)
            res = func(*args,**kwargs)
            return res
        return wrapper
    return deco

# 有参装饰器使用
@outter(111)
def index():
    pass

1.3.2 有参装饰器实战案例(动态数据源权限校验)

通过传入参数动态指定校验数据源,支持file、mysql、ldap多种校验模式,实现装饰器功能复用。

def outter(engine,xxx):
    def auth(func):
        def wrapper(*args, **kwargs):
            print(xxx)
            username = input("username>>>: ").strip()
            password = input("password>>>: ").strip()

            if engine == "file":
                print("账号密码存放在文件中")
                if username == "egon" and password == "123":
                    print("登录成功")
                    res = func(*args, **kwargs)
                    return res
                else:
                    print("账号或密码错误")

            elif engine == "mysql":
                print("账号密码存放在数据库中")

            elif engine == "ldap":
                print("账号密码存放在ldap")
            else:
                print("未知engine")
        return wrapper
    return auth

# 传入参数指定mysql数据源模式
@outter('mysql',111)
def index():
    print('from index ....')

index()

二、迭代器

2.1 迭代器核心概念

迭代:是重复执行的过程,且每一次重复操作都基于上一次的结果,区别于单纯的无逻辑重复。

迭代器:是Python中通用的迭代取值工具,核心作用是提供不依赖索引的通用取值方案,适配所有可迭代数据类型。

2.1.1 迭代与普通重复的区别

单纯重复(非迭代):无状态继承,每次执行相互独立

i = 0
while i < 5:
    print(i)

真正迭代:基于上一次结果更新状态,逐步推进

i = 0
names = ["egon","lili",'jack']
while i < len(names):
    print(i,names[i])
    i += 1

2.2 迭代器的存在意义

Python中字符串、列表、元组、字典、集合、文件对象,均需要迭代取值。传统索引取值方式仅支持有序序列类型(字符串、列表、元组),无法适配字典、集合等无序类型。迭代器屏蔽数据类型差异,提供统一、通用的迭代取值方案。

2.3 可迭代对象与迭代器对象

2.3.1 可迭代对象(iterable)

定义:内置有__iter__()方法的对象,统称为可迭代对象。

常见可迭代对象:str、list、tuple、dict、set、文件对象。

特性:可迭代对象调用__iter__()方法,可转换为迭代器对象。

2.3.2 迭代器对象(iterator)

定义:同时内置__iter__()和__next__()方法的对象。

核心方法:

next():取出迭代器中的下一个值,取值完毕后继续调用会抛出StopIteration异常

iter():返回迭代器自身,无实际迭代逻辑变更

核心关系:迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象。文件对象是原生迭代器对象。

2.3.3 迭代器取值示例

# 字典迭代取值
dic = {"a": 1, 'b': 222, 'c': 333}
dic_iterator = dic.__iter__()

# 单次取值
print(dic_iterator.__next__())
print(dic_iterator.__next__())
print(dic_iterator.__next__())

# 循环捕获异常取值(通用方案)
dic_iterator = dic.__iter__()
while True:
    try:
        print(dic_iterator.__next__())
    except StopIteration:
        break

# 迭代器一次性特性:取值完毕后无法再次取值
print("迭代器取值完毕,二次迭代无效")
for k in dic_iterator:
    print(k)

2.4 for循环底层工作原理

for循环本质是迭代器循环,底层完全基于迭代器实现,自动完成迭代、取值、异常捕获,无需手动处理StopIteration异常。

for循环执行流程:

1、调用in后可迭代对象的__iter__()方法,生成迭代器对象;

2、循环调用迭代器的__next__()方法,取值并赋值给循环变量,执行循环体;

3、捕获StopIteration异常,自动终止循环。

# for循环迭代字典
dic = {"a": 1, 'b': 222, 'c': 333}
for k in dic:
    print(k)

# 文件对象迭代(原生迭代器)
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line.strip())
    # 迭代器取值完毕,二次循环无输出
    print("二次读取文件内容:")
    for line in f:
        print(line.strip())

2.5 迭代器的优缺点

2.5.1 优点

1、通用性强:统一有序、无序数据类型的迭代取值方案,是for循环实现的底层基础;

2、节省内存:惰性计算,同一时刻内存中仅保留一个迭代值,可处理无限数据流,区别于列表、字典等全量加载数据的容器类型。

2.5.2 缺点

1、无法预知长度:迭代器未取值完毕前,无法获取总数据量;

2、一次性取值:迭代器状态单向推进,取值完毕后彻底失效,无法回溯、重复迭代,多循环共用同一个迭代器时,仅第一个循环可取值。

三、生成器

3.1 生成器核心概念

生成器本质是自定义的迭代器,是开发者通过代码手动创建的迭代器,拥有原生迭代器所有特性,同时支持自定义迭代逻辑,灵活性远超原生迭代器。

3.2 生成器的存在意义

原生迭代器仅支持系统内置数据类型迭代,逻辑固定无法修改。生成器允许开发者自定义迭代规则,结合迭代器惰性计算、节省内存的核心优势,可按需生成无限数据流,适配大数据批量处理、流式数据读取等场景。

3.3 生成器创建与执行原理

创建规则:函数内部只要包含yield关键字,该函数就不再是普通函数,调用函数不会执行函数体,而是直接返回一个生成器对象(自定义迭代器)。

执行规则:通过__next__()触发生成器执行,代码运行至yield处暂停,返回yield后的值;再次触发__next__(),从暂停位置继续执行,直至无yield关键字,抛出StopIteration异常。

3.3.1 基础生成器示例

def func():
    print("111111")
    yield 1
    print("222222")
    yield 2
    print("333333")
    yield 3
    print("4444444")

# 生成生成器对象,不执行函数体
g = func()
# 触发执行,分段取值
print(g.__next__())
print(g.__next__())
print(g.__next__())
# 取值完毕,触发异常
# print(g.__next__())

3.4 自定义range生成器案例

基于生成器原理,复刻Python内置range函数的迭代逻辑,实现自定义数值迭代器。

def my_range(start, stop, step=1):
    print("start...")
    while start < stop:
        yield start
        start += step
    print("stop...")

# 创建生成器
g = my_range(1, 5, 2)
# for循环迭代取值
for item in g:
    print(item)
# 生成器取值完毕,二次迭代无输出
print("======")
for item in g:
    print(item)

3.5 yield与return的核心区别

相同点:均可返回任意类型、任意数量的数据。

不同点:

1、return:一个函数仅支持一个return,执行return后函数立即终止,仅能返回一次值;

2、yield:一个函数支持多个yield,执行yield后函数暂停、保存运行状态,可多次返回值,实现分段迭代。

3.6 生成器send方法(传值交互)

send()是生成器专属方法,不仅可以触发生成器继续执行,还可以向暂停的yield位置传递参数,实现生成器内外数据交互,是生成器高级用法。

使用规则:首次调用必须传send(None),初始化生成器至yield暂停状态,后续可传递任意参数。

def eater(name):
    print("%s 准备开始吃饭啦" % name)
    food_list = []
    while True:
        food = yield food_list
        print("%s 吃了 %s" % (name, food))
        food_list.append(food)

g = eater("egon")
# 初始化生成器
res = g.send(None)
print(res)
# 向生成器传值
res = g.send("蒸羊羔")
print(res)
res = g.send("蒸鹿茸")
print(res)

# 关闭生成器,后续无法传值执行
# g.close()
# g.send("蒸熊掌")
posted @ 2026-07-14 10:57  cuckooyang  阅读(12)  评论(0)    收藏  举报