Сложнее, чем нужно, чтобы точно увидеть, что происходит с вашим кодом, потому что вы выбрали непонятные имена при написании вашего декоратора. Вот версия, которая делает то же самое, что и ваш код, с измененными именами:
def head_and_foot(func):
def wrapper(func):
print(func.__name__)
func()
print("End of", func.__name__, "\n\n")
return wrapper(func)
def price_report():
cars = ['Celerio', 'i10', 'Amaze', 'Figo']
price = [500_000, 350_000, 800_000, 550_000]
for x, y in zip(cars, price):
print(f'{x:8s}', f'{y:8,d}')
def sales_report():
cars = ['Celerio', 'i10', 'Amaze', 'Figo']
units = [5000, 3000, 1000, 800]
for x, y in zip(cars, units):
print(f'{x:8s}', f'{y:8,d}')
sales_report = head_and_foot(sales_report)
price_report = head_and_foot(price_report)
Здесь есть три изменения:
wrapper
→ head_and_foot
head_and_foot
→ wrapper
report
→ func
Функция, которую вы назвали wrapper
, которую я переименовал в head_and_foot
, является декоратором . Это означает, что она принимает функцию в качестве аргумента и возвращает другую функцию, которая предназначена для замены принятой.
Обычно функция замены, которую она возвращает, является оболочкой для исходной функции, что означает, что она делает то же самое, что и исходная функция, заключенная в некоторые дополнительные действия.
Чтобы сохранить все это, принято вызывать декоратор по имени, описывающему его эффект (например, head_and_foot
, вызывать функцию, которую он принимает func
, и вызывать оболочку, которую он возвращает wrapper
. Это то, что я ' мы сделали выше.
После того, как у вас появятся разумные имена, вам будет легче понять, что у вас есть две проблемы:
wrapper
должен быть заменой для декорируемых функций, поэтому он должен иметь такую же сигнатуру - это означает, что он должен принимать то же число и тип аргументов. Ваши функции price_report
и sales_report
вообще не принимают никаких аргументов (т. Е. Между скобками ()
в их выражении def
нет ничего), но wrapper
принимает функцию, которую предполагается заменить, в качестве аргумента, что не имеет никакого смысла.
Эта строка должна быть просто def wrapper():
, чтобы соответствовать сигнатуре заменяемых функций.
Предполагается, что декоратор возвращает функцию замены, но ваш декоратор вызывает замену и возвращает результат. Вместо return wrapper(func)
вам просто нужно return wrapper
.
После внесения обоих этих изменений мы получаем следующее:
def head_and_foot(func):
def wrapper():
print(func.__name__)
func()
print("End of", func.__name__, "\n\n")
return wrapper
def price_report():
cars = ['Celerio', 'i10', 'Amaze', 'Figo']
price = [500_000, 350_000, 800_000, 550_000]
for x, y in zip(cars, price):
print(f'{x:8s}', f'{y:8,d}')
def sales_report():
cars = ['Celerio', 'i10', 'Amaze', 'Figo']
units = [5000, 3000, 1000, 800]
for x, y in zip(cars, units):
print(f'{x:8s}', f'{y:8,d}')
sales_report = head_and_foot(sales_report)
price_report = head_and_foot(price_report)
Когда мы запускаем этот фиксированный код, мы не получаем неожиданного вывода, но мы получаем две функции, которые делают то, что мы ожидаем:
>>> price_report()
price_report
Celerio 500,000
i10 350,000
Amaze 800,000
Figo 550,000
End of price_report
>>> sales_report()
sales_report
Celerio 5,000
i10 3,000
Amaze 1,000
Figo 800
End of sales_report