You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于《Python Cookbook》9.5节装饰器中functools.partial用法的疑问

理解attach_wrapper中functools.partial的作用

我当初第一次看到这段代码的时候也有点懵,咱们一步步拆开来理清楚它的逻辑和价值。

首先得明确:这个attach_wrapper工具的核心目的,是让你能用装饰器语法,把一个函数快速绑定成另一个对象的属性,不用每次手动写setattr(obj, func.__name__, func)这种重复代码。

先拆解代码逻辑

咱们把attach_wrapper的两种调用情况分开看:

  1. 当同时传obj和func时:直接执行setattr(obj, func.__name__, func),把func以自身名字为属性名,挂载到obj上,最后返回func(不影响原函数的其他使用)。
  2. 只传obj,func为None时:返回一个functools.partial(attach_wrapper, obj)——这个偏函数已经“记住”了第一个参数是obj,后面只需要给它传func,它就会自动调用attach_wrapper(obj, func)。

为什么需要用partial?关键是适配装饰器语法

这才是重点!装饰器语法要求@后面必须是一个能接收函数的对象(比如另一个函数)。如果没有partial,你想给装饰器的wrapper绑定辅助方法,只能手动写setattr:

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("执行前预处理")
        return func(*args, **kwargs)
    
    # 手动给wrapper加unwrap方法
    def unwrap():
        return func
    setattr(wrapper, 'unwrap', unwrap)
    
    return wrapper

但用attach_wrapper配合partial,就能把这个过程改成更优雅的装饰器形式:

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("执行前预处理")
        return func(*args, **kwargs)
    
    # 用装饰器语法给wrapper绑定unwrap方法
    @attach_wrapper(wrapper)
    def unwrap():
        return func
    
    return wrapper

这里@attach_wrapper(wrapper)等价于:

unwrap = attach_wrapper(wrapper)(unwrap)

因为attach_wrapper(wrapper)返回的偏函数,正好接收unwrap作为func参数,自动完成setattr(wrapper, 'unwrap', unwrap)的操作,完美适配装饰器语法糖,代码看起来整洁多了。

关于“防止属性遮蔽”的疑问

不完全是,但它确实能帮你在多层装饰器嵌套时,更安全地给每个层级的wrapper附加属性。比如当你用多个装饰器包裹一个函数时,每个装饰器都可以用@attach_wrapper(wrapper)给当前的wrapper加方法,只要方法名不重复,就不用担心手动setattr会不小心覆盖上层的属性。本质上,它是简化了“给对象动态绑定方法”的操作,让这个操作在复杂的装饰器组合中保持可读性和可维护性。

举个多层装饰器的例子感受下:

def decorator1(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Decorator 1 生效")
        return func(*args, **kwargs)
    
    @attach_wrapper(wrapper)
    def info1():
        return "来自Decorator 1的信息"
    
    return wrapper

def decorator2(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Decorator 2 生效")
        return func(*args, **kwargs)
    
    @attach_wrapper(wrapper)
    def info2():
        return "来自Decorator 2的信息"
    
    return wrapper

@decorator1
@decorator2
def add(a, b):
    return a + b

现在add.info1()和add.info2()都能正常调用,每个装饰器的方法都被正确绑定到了对应的wrapper上,整个过程清晰又省心。

内容的提问来源于stack exchange,提问作者Matt Eding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:07:27