2015-06-25 4 views
2

Рассмотрим этого модуля:Использования декорированной функции по умолчанию аргументов функции

#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. Но почему он не печатает «начало» и «конец»?

+0

Это ваш регистратор, я почти полностью уверен. Причина, по которой я говорю, что если вы добавите инструкцию печати в оболочку, вы увидите, что она вызвана для f (3). –

ответ

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

Проблема заключается в том, что значение по умолчанию оценивается немедленно, до регистратор инициализирован. Путь к этому заключается в том, чтобы отсрочить исполнение до следующего.

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

Но использование «лямбда» по умолчанию тоже странно. Что делать, если я передаю действительный целочисленный параметр? Вместо этого, возможно, сделайте что-то вроде 'def g (y = None): если y - None: y = f (3)'. Используя «lambda», вы неявно изменяете тип параметра на «вызываемый». –

+0

Несомненно, это также относится к оценке. –

Смежные вопросы