#python #python-3.x #decorator
#python #python-3.x #декоратор
Вопрос:
Я новичок в Python, и я только что столкнулся с декораторами. Я все еще немного смущен ими, но я учусь
я пытался создать декоратор, который сообщал бы мне, сколько времени потребовалось для завершения моей функции, но, видимо, когда я пытаюсь использовать его для функции, которая должна что-то возвращать, она просто возвращает «None»
Я видел только пару вопросов, в которых говорилось об этой проблеме, но ни один из них на самом деле не помог
Вот мой код
import time
def time_it(func): # Here i make a simple decorator function that should time my decorated function
def wrapper(*args, **kwargs):
t1 = time.time()
func(*args)
t2 = time.time()
total = t2 - t1
print("The function '" func.__name__ "' took", str(total)[0:5], "seconds to complete")
return wrapper
@time_it
def square(nums): # I make a function that squares every number in a list
new_list = []
for n in nums:
new_list.append(n ** 2)
return new_list
lis = [f for f in range(200000)] # i make a list with a range of 200000
print(square(lis))
извините за любые грамматические ошибки, я не являюсь носителем английского языка
Комментарии:
1. Да, потому что
wrapper
всегда возвращаетNone
.
Ответ №1:
Проблема в том, что возвращаемое значение вашей внутренней функции не возвращается. Изменение отмечено ниже:
from functools import wraps
def time_it(func): # Here i make a simple decorator function that should time my decorated function
@wraps(func)
def wrapper(*args, **kwargs):
t1 = time.time()
## Note the change on this line -- I now store the return result from the called function
result = func(*args, **kwargs)
t2 = time.time()
total = t2 - t1
print("The function '" func.__name__ "' took", str(total)[0:5], "seconds to complete")
## And then explicitly return the result
return result
return wrapper
Для декоратора вам нужно помнить, что это просто замыкание с некоторым причудливым синтаксисом. Вам все равно нужно разобраться с параметрами возврата функции самостоятельно.
Пара дополнений:
from functools import wraps
и@wraps(func)
- это создаст обертку внутренней функции с некоторыми деталями, которые существуют в функции обертывания. В документации Python здесь есть небольшой пример:https://docs.python.org/3/library/functools.html
Комментарии:
1. Вероятно, также лучше, чтобы OP использовал все аргументы, например:
result = func(*args, **kwargs)
на всякий случай… Также не помешало бы использоватьfunctools.wraps
и здесь…2. Да, вы правы. Я обновил пример, чтобы отразить это. Спасибо!
Ответ №2:
Декоратор заменяет square
на wrapper
и wrapper
ничего не возвращает. Она должна возвращать значение, возвращаемое обернутой функцией.
Это правильный способ сделать это:
def time_it(func):
def wrapper(*args, **kwargs):
t1 = time.time()
try:
return func(*args, **kwargs)
finally:
t2 = time.time()
total = t2 - t1
print("The function '" func.__name__ "' took", str(total)[0:5], "seconds to complete")
return wrapper
Я изменил 3 вещи:
- добавлено
return
, чтобы значение возвращалось из оформленной функции - добавлено
**kwargs
вfunc
вызовы, потому что это может потребоваться при использовании по-другому - добавлен
try
/finally
блок, так что распечатка происходит даже в случае исключения, плюс это упрощает возврат значения.
Ответ №3:
Ваша оформленная функция ничего явно не возвращает — поэтому по умолчанию она возвращает None
.
Вы можете записывать выходные данные перед печатью времени и возвращать в конце:
def time_it(func): # Here i make a simple decorator function that should time my decorated function
def wrapper(*args, **kwargs):
t1 = time.time()
out = func(*args)
t2 = time.time()
total = t2 - t1
print("The function '" func.__name__ "' took", str(total)[0:5], "seconds to complete")
return out
return wrapper