将函数__dict__项分配给functool.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,则f.foo = "bar"关系是"0">断裂";

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

我意识到我可以通过p.func.foo访问它。但我很好奇,当使用分部时,是否有更好的方法来重建关系。

尝试的解决方案

下面的变通方法似乎是">工作";,但我很好奇是否有更好的方法。重写__new__很奇怪,所以我选择重写__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"

如果你提前计划,你可以单独装饰函数的部分版本:

def func(a: int, b: int) -> int:
return a + b
p = decorator()(partial(func, 1))
func = decorator()(func)

如果你不介意单独的p.foofunc.foo的存在,你也可以只装饰部分。

对于创建新函数(而不是在原始函数上设置属性(的装饰器,可以使用functools.wraps,以便函数在__wrapped__属性中记住其原始函数,并对其进行局部和重新装饰:

from functools import partial, wraps
def get_name(func):
try:
return func.__name__
except AttributeError: # handle a partial
return 'a partial application of ' + get_name(func.func)
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"this is a decorated version of {get_name(func)}")
return func(*args, **kwargs)
return wrapper
@decorator
def decorated_sum(x, y):
return x + y
increment = decorator(partial(decorated_sum.__wrapped__, 1))

您甚至可以创建一个助手函数来查找__wrapped__属性,但您需要构建自己的方法来确定要应用哪些装饰器。

相关内容

  • 没有找到相关文章

最新更新