Python 3-装饰器执行流程

时间:2018-09-04 22:57:09

标签: python python-decorators

以下示例摘自python Cookbook第三版9.5节。 我在每一行都放置了断点,以了解执行流程。以下是代码示例,其输出和我所遇到的问题。我试图解释我的问题,如果需要更多信息,请告诉我。

<input id="test1" value="1" />
<button onclick="kontakte('firstname', 10)">KLICK1</button>
<input id="test2" value="2" />
<button onclick="kontakte('secondname', 12)">KLICK2</button>
<input id="test3" value="3" />
<button onclick="kontakte('thirdname', 1138)">KLICK3</button>

function kontakte(name, price) {
    alert(name + ", " + price);
}

输出为

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))

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

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

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

方案2 :执行 @attach_wrapper(wrapper)时,控件将执行 attach_wrapper(obj,func = None)和部分函数返回      func =

问题:为什么控件会返回执行 def attach_wrapper(obj,func = None):  以及这一次func的值如何在0x000000000处为* .decorate..set_message>  被传递给attach_wrapper吗?

1 个答案:

答案 0 :(得分:2)

场景1

此:

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

与此相同:

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

请注意,这里有两个调用:首先logged(logging.DEBUG)返回decorate,然后调用decorate(add)

场景2

方案1 中的相同,

@attach_wrapper(wrapper)
def set_message(newmsg):
    ...

与此相同:

def set_message(newmsg):
    ...
set_message = attach_wrapper(wrapper)(set_message)

同样,有两个调用:首先attach_wrapper(wrapper)返回partial对象,然后调用partial(set_message)


换句话说...

loggedattach_wrapper不是装饰器。这些是返回装饰器的函数。这就是为什么要进行两次调用:一个调用返回装饰器的函数,另一个调用装饰器本身。