加载中...

python 装饰器,生成器

装饰器

本质上也是一个函数,可以让被装饰的函数在原代码不变的情况下添加新功能。

优点:复用性强,当多个函数需要相同的额外功能时,直接将该功能封装在一个装饰函数中,需要该额外功能的其他函数直接用装饰器修饰即可。

模板:

def decorator(func):
    def wrapper(*arg, **kwarg):
        ...
    return wrapper

生成器

最大特点是:不一次性生成所有值,而是按需生成值。

优点:提高内存效率,适合处理大型数据

a = [x * x for x in range(10000)]
b = (x * x for x in range(10000)) 

上述代码中,\(a\) 是一个普通的列表,而 \(b\) 是一个生成器。显然对于 \(a\)\(0 \backsim 9999\) 的平方都会被创建;而 \(b\) 中的对象会在循环枚举(不能按下标取值)时动态生成,枚举到哪个就生成哪个。

创建生成器的两种方式:

  • 圆括号
  • \(yield\)

对于一个函数:

def f(*arg):
    ...
  • \(f\):表示函数本身
  • \(f(*arg)\):表示一个生成器

与生成器相关的一些函数:

  • \(yield\):暂停执行,并返回后面的值。
  • \(next\):从刚才暂停的地方继续执行,直到遇到下一个 \(yield\)
  • \(send\):为生成器发送一个值

在函数体内,\(return\)\(yield\) 的区别:

  • \(yield\):保存函数内的局部变量,保持当前的执行状态,暂停函数执行,并产出一个值给调用者。
  • \(return\):立即终止函数的执行,并返回一个值给调用者。

以竞赛头模块的 \(dfs\) 部分为例,深入理解装饰器和生成器:

from types import GeneratorType

def bootstrap(f, stk=[]):
    def wrappedfunc(*args, **kwargs):
        if stk:
            return f(*args, **kwargs)
        else:
            to = f(*args, **kwargs)
            while True:
                if type(to) is GeneratorType:
                    stk.append(to)
                    to = next(to)
                else:
                    if stk:
                        stk.pop()
                    if not stk:
                        break
                    to = stk[-1].send(to)
            return to
    return wrappedfunc

调用装饰器的部分:

@bootstrap
def dfs(*arg):
    ...
        yield dfs(...)

    yield x

\('@...'\) 就是一个语法糖,实际上完全等价于:

dfs = bootstrap(dfs)

其中 \(bootstrap\) 是一个包装函数的函数,在本模块中作用是将 \(dfs\) 的递归调用转化成栈模拟的过程,以加大递归深度,避免爆栈。

关于装饰器 '@bookstrap' 的使用:

需要在所有 \(return\) 的地方加上 \(yield\),使得函数不再像普通函数一样调用,而是产生一个生成器并将其压栈,并继续后续处理。特殊地,若\(dfs\) 函数是 \(None\) 类型,还需要注意在函数结尾添加一个 \(yield\)
eg:

@bootstrap
    def dfs(u:int, father:int):
        dep[u] = dep[father] + 1
        for v in G[u]:
            if v == father: continue
            yield dfs(v, u) # 每个dfs递归调用前面都需要补充一个 yield
        yield # 注意这里,隐式return也需要补充yield
posted @ 2026-05-08 10:48  小橘奏  阅读(15)  评论(0)    收藏  举报