Python 3 - 装饰器执行流程

问题描述 投票:1回答:1

以下示例取自python cookbook第3版第9.5节。我在每一行都设置了断点来理解执行流程。下面是代码示例,其输出和我的问题。我试图解释我的问题,如果您需要进一步的信息,请告诉我。

from functools import wraps, partial
import logging

# Utility decorator to attach a function as an attribute of obj
def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func

def logged(level, name=None, message=None):


    def decorate(func):
        logname = name if name else func.__module__
        log = logging.getLogger(logname)
        logmsg = message if message else func.__name__

        @wraps(func)
        def wrapper(*args, **kwargs):
            log.log(level, logmsg)
            return func(*args, **kwargs)


        @attach_wrapper(wrapper)
        def set_message(newmsg):
            nonlocal logmsg
            logmsg = newmsg


        return wrapper
    return decorate

# Example use
@logged(logging.DEBUG)
def add(x, y):
    return x + y


logging.basicConfig(level=logging.DEBUG)
add.set_message('Add called')
#add.set_level(logging.WARNING)
print (add(2, 3))

输出是

DEBUG:__main__:Add called
5

我理解装饰器的概念,但这有点令人困惑。

场景1.当调试以下行@logged(logging.DEBUG)时,我们得到decorate = .decorate at 0x000000000 <memoryaddress >>

问题:为什么控制会返回执行“def decorate”功能?是因为“装饰”功能位于堆栈的顶部吗?

场景2:执行@attach_wrapper(包装器)时,控件执行attach_wrapper(obj,func = None),部分函数返回func =

问题:为什么控制会返回执行def attach_wrapper(obj,func = None):这次func的值是如何将* .decorate..set_message在0x000000000>传递给attach_wrapper?

python python-decorators
1个回答
2
投票

Scenario 1

这个:

@logged(logging.DEBUG)
def add(x, y):
    ....

与此相同:

def add(x, y):
    ....
add = logged(logging.DEBUG)(add)

请注意,有两个调用:第一个qazxsw poi返回qazxsw poi然后调用qazxsw poi。

Scenario 2

与场景1相同,这个:

logged(logging.DEBUG)

与此相同:

decorate

同样,有两个调用:第一个decorate(add)返回@attach_wrapper(wrapper) def set_message(newmsg): ... 对象,然后调用def set_message(newmsg): ... set_message = attach_wrapper(wrapper)(set_message)


In other words...

attach_wrapper(wrapper)partial不是装饰者。这些是返回装饰器的函数。这就是为什么要进行两次调用的原因:一个是返回装饰器的函数,另一个是装饰器本身。

© www.soinside.com 2019 - 2024. All rights reserved.