Python 为什么使用partial向函数添加属性

Python 为什么使用partial向函数添加属性,python,python-decorators,Python,Python Decorators,前几天我读了这篇文章,我不明白为什么在“日志装饰器”一节中使用了partial: attach\u wrapper未设置,用于在包装另一个函数的函数上设置某些属性: @attach_wrapper(wrapper) # Attaches "set_level" to "wrapper" as attribute def set_level(new_level): # Function that allows us to set log level

前几天我读了这篇文章,我不明白为什么在“日志装饰器”一节中使用了
partial

attach\u wrapper
未设置,用于在包装另一个函数的函数上设置某些属性:

@attach_wrapper(wrapper)  # Attaches "set_level" to "wrapper" as attribute
def set_level(new_level):  # Function that allows us to set log level
    nonlocal level
    level = new_level

为什么不能用
setattr
直接在
wrapper
上设置这些属性?

如果插入
attach\u wrapper
,可以看到它的
func
参数是
None

def attach_wrapper(obj, func=None):  # Helper function that attaches function as attribute of an object
    if func is None:
        print(f'obj is {obj.__name__} - func is',func)
        return partial(attach_wrapper, obj)
    print(f'a_w:obj is {obj.__name__} - func is {func.__name__}')
    setattr(obj, func.__name__, func)
    return func
然后

导致

>>>
obj is somefunc - func is None
a_w:obj is somefunc - func is set_level
obj is somefunc - func is None
a_w:obj is somefunc - func is set_message
>>>

attach\u wrapper
被调用两次。它的
func
第一次是
None
,它返回一个分部函数
attach\u wrapper
,其第一个参数
obj
设置为
some\u func
。然后调用分部(装饰器机制的所有部分),并对函数进行装饰

attach\u wrapper的
obj
看起来像
some\u func
,但实际上它是
some\u func
wrapper
包装的-它的外观和感觉都是一样的,因为这就是它的用途


下面是将
inspect.stack
添加到仪器的更多细节

产生

>>>
called from:  @attach_wrapper(wrapper)  # Attaches "set_level" to "wrapper" as attribute
    by function  decorate
    obj is somefunc, func is None

called from:  def set_level(new_level):  # Function that allows us to set log level
    by function  decorate
    obj is somefunc, func is set_level

called from:  @attach_wrapper(wrapper)  # Attaches "set_message" to "wrapper" as attribute
    by function  decorate
    obj is somefunc, func is None

called from:  def set_message(new_message):  # Function that allows us to set message
    by function  decorate
    obj is somefunc, func is set_message

>>>


这里有一些更详细的解释。如果我找到一个,我将进行更新。

它的使用方式是,如果调用
attach\u wrapper
函数时没有要包装的函数,它将返回一些东西,然后您可以使用其他函数调用这些东西,以便将多个附加到目标对象。例如,如果您有三个函数
f
g
h
,以及一个对象
foo
,您可以使用
attach\u to\u foo=attach\u wrapper(foo)
创建一个“attacher”,然后将其与
attach\u to\u foo(f)
attach\u to\u foo(g)
attach\u to\u foo(h)一起使用
foo.f
foo.g
foo.h
结束

>>>
obj is somefunc - func is None
a_w:obj is somefunc - func is set_level
obj is somefunc - func is None
a_w:obj is somefunc - func is set_message
>>>
import inspect

def attach_wrapper(obj, func=None):  # Helper function that attaches function as attribute of an object
    print("called from: ", inspect.stack()[1].code_context[0].strip())
    print("\tby function ", inspect.stack()[1].function)
    if func is None:
        print(f'\tobj is {obj.__name__}, func is {func}\n')
        return partial(attach_wrapper, obj)
    print(f'\tobj is {obj.__name__}, func is {func.__name__}\n')
    setattr(obj, func.__name__, func)
    return func
>>>
called from:  @attach_wrapper(wrapper)  # Attaches "set_level" to "wrapper" as attribute
    by function  decorate
    obj is somefunc, func is None

called from:  def set_level(new_level):  # Function that allows us to set log level
    by function  decorate
    obj is somefunc, func is set_level

called from:  @attach_wrapper(wrapper)  # Attaches "set_message" to "wrapper" as attribute
    by function  decorate
    obj is somefunc, func is None

called from:  def set_message(new_message):  # Function that allows us to set message
    by function  decorate
    obj is somefunc, func is set_message

>>>