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

如何将被装饰函数的__dict__属性传递给functools.partial实例?

如何让functools.partial继承原函数的自定义属性?

问题背景

我们有一个自定义装饰器,会给被装饰的函数添加自定义属性:

from typing import Callable

def decorator() -> Callable:
    def wrapper(f: Callable) -> Callable:
        f.foo = "bar"
        return f
    return wrapper

@decorator()
def func(a: int, b: int) -> int:
    return a + b

正常调用时,我们可以直接访问函数的自定义属性:

>>> func.foo
"bar"
>>> func(1,2)
3

但当使用functools.partial包装函数后,无法直接通过partial实例访问原函数的自定义属性:

>>> from functools import partial
>>> p = partial(func, a=1)
>>> p(b=2)
3
>>> p.foo
AttributeError: 'partial' object has no attribute 'foo'

虽然可以通过p.func.foo访问属性,但希望找到更直观的方式,让partial实例能直接继承原函数的自定义属性。

现有临时方案

目前尝试了继承partial并重写__init__的方式,在初始化时复制原函数的属性:

class new_partial(partial):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for k, v in self.func.__dict__.items():
            setattr(self, k, v)

使用该类包装后可以直接访问属性:

>>> p = new_partial(func, a=1)
>>> p(b=2)
3
>>> p.foo
"bar"

但这种方式存在局限性:初始化时复制的属性是静态的,如果原函数的属性后续发生变化,partial实例不会同步更新;另外partial的实例是在__new__方法中创建的,重写__init__的方式不够规范。

更优解决方案

方案1:通过__getattr__动态代理属性

继承partial并重写__getattr__方法,当访问partial实例不存在的属性时,自动去原函数中查找:

from functools import partial

class PartialWithAttrs(partial):
    def __getattr__(self, name):
        # 先尝试自身属性,不存在则代理到原函数
        try:
            return super().__getattr__(name)
        except AttributeError:
            return getattr(self.func, name)

使用示例:

>>> p = PartialWithAttrs(func, a=1)
>>> p(b=2)
3
>>> p.foo
"bar"
# 原函数属性更新后,partial实例也能拿到最新值
>>> func.foo = "new_bar"
>>> p.foo
"new_bar"

这种方式的优势:

  • 无需提前复制属性,内存更高效
  • 原函数属性更新时,partial实例会自动同步
  • 符合Python的属性查找逻辑,行为更直观

方案2:函数式包装partial

如果不想创建自定义类,可以用函数包装partial,在创建partial实例后复制原函数的属性:

from functools import partial

def partial_with_attrs(func, *args, **kwargs):
    p = partial(func, *args, **kwargs)
    # 只复制partial实例没有的属性
    for attr_name, attr_value in func.__dict__.items():
        if not hasattr(p, attr_name):
            setattr(p, attr_name, attr_value)
    return p

使用示例:

>>> p = partial_with_attrs(func, a=1)
>>> p.foo
"bar"

这种方式更轻量,但同样是静态复制属性,原函数属性更新后不会同步到partial实例。

总结

如果需要属性动态同步,优先选择方案1(__getattr__动态代理);如果只需要初始化时复制属性,且不想自定义类,可以选择方案2(函数式包装)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 06:03:18