使用修饰函数作为函数的默认参数

时间:2015-06-25 14:22:36

标签: python python-2.7 logging decorator python-decorators

考虑这个模块:

#mymodule.py
import logging

def print_start_end(name):
    """
    Decorator that creates a logger and logs the start 
    and the end of the function call
    """
    def decorator(f):
        logger = logging.getLogger(name)
        def wrapper(*args, **kwargs):
            logger.info("start")
            res = f(*args, **kwargs)
            logger.info("end")
            return res
        return wrapper
    return decorator

@print_start_end(__name__)
def f(x):
    return x

def g(y=f(3)):
    return y

示例脚本:

import logging
from mymodule import f

logger = logging.getLogger("")
logger.setLevel(logging.INFO)
h = logging.StreamHandler()
h.setLevel(logging.INFO)
logger.addHandler(h)

print f(3)

输出:

start
end
3

装饰师正在工作。但现在我编写了一个脚本来使用g而不是f

import logging
from mymodule import g

logger = logging.getLogger("")
logger.setLevel(logging.INFO)
h = logging.StreamHandler()
h.setLevel(logging.INFO)
logger.addHandler(h)

print g()

输出:

3

执行语句print g()时,对f的调用成功,因为它打印了预期的返回值3.但为什么它也不打印" start"和"结束"?

2 个答案:

答案 0 :(得分:1)

问题是,在初始化记录器之前,会立即评估默认值。解决这个问题的方法是将执行推迟到之后。

def g(y=lambda:f(3)):
    return y()

答案 1 :(得分:1)

请注意f(3)中的def g(y=f(3)):仅在定义函数时执行,而不是每次调用函数时都执行

因此,问题似乎是在f(3)中执行mymodule时,记录器尚未初始化。首先初始化,然后导入,然后它可以工作:

import logging

logger = logging.getLogger("")
logger.setLevel(logging.INFO)
h = logging.StreamHandler()
h.setLevel(logging.INFO)
logger.addHandler(h)

from mymodule import g

print g()