【问题标题】:Python 3 - Decorators execution flowPython 3 - 装饰器执行流程
【发布时间】:2019-02-09 23:59:51
【问题描述】:

以下示例取自 python 食谱第 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>

问题:为什么控件会返回执行“def decorate”函数?是不是因为“装饰”函数在栈顶?

场景2 :执行@attach_wrapper(wrapper)时,控制去执行attach_wrapper(obj, func=None)和partial函数返回 函数 =

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

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    场景 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 不是装饰器。这些是返回装饰器的函数。这就是为什么要进行两次调用:一个调用返回装饰器的函数,另一个调用装饰器本身。

    【讨论】:

    • 很好的解释。
    猜你喜欢
    • 2016-07-25
    • 2015-09-17
    • 2012-01-20
    • 2013-08-21
    • 2023-03-04
    • 2023-04-06
    • 2015-02-05
    • 1970-01-01
    相关资源
    最近更新 更多