Что такое декоратор в python
Перейти к содержимому

Что такое декоратор в python

  • автор:

Что такое декораторы в Python

Декораторы в Python — это мощный инструмент, который позволяет модифицировать поведение функций или классов без изменения их кода. Они представляют собой функции высшего порядка, то есть функции, которые принимают другие функции в качестве аргументов и возвращают новые функции. В Python декораторы обычно применяются с помощью синтаксиса @decorator перед определением функции или класса.

Как создать декоратор

Создание декоратора в Python происходит в несколько этапов. Рассмотрим пример создания простого декоратора, который выводит информацию о вызове функции:

  1. Определите функцию-декоратор, которая принимает в качестве аргумента другую функцию:
def my_decorator(func): .
  1. Внутри функции-декоратора определите новую функцию (обычно называемую «wrapper» или «обертка»), которая будет выполнять дополнительные действия перед и/или после вызова исходной функции:
def my_decorator(func): def wrapper(): print("Что-то происходит перед вызовом функции") func() print("Что-то происходит после вызова функции") return wrapper
  1. Верните из функции-декоратора новую функцию-обертку:
def my_decorator(func): def wrapper(): . return wrapper
  1. Теперь можно применить созданный декоратор к любой функции с помощью синтаксиса @decorator :
@my_decorator def say_hello(): print("Привет, мир!") say_hello()

В результате выполнения кода мы увидим следующий вывод:

Что-то происходит перед вызовом функции Привет, мир! Что-то происходит после вызова функции 

Python-разработчик: новая работа через 9 месяцев
Получится, даже если у вас нет опыта в IT

Пример использования декоратора

Рассмотрим пример использования декоратора для измерения времени выполнения функции:

import time def timing_decorator(func): def wrapper(): start_time = time.time() func() end_time = time.time() print(f"Функция выполнялась секунд") return wrapper @timing_decorator def some_long_running_function(): time.sleep(2) print("Функция завершила работу") some_long_running_function()

В данном примере декоратор timing_decorator измеряет время выполнения функции some_long_running_function и выводит результат на экран.

Заключение

Декораторы в Python — это удобный способ добавления нового поведения к функциям или классам без изменения их кода. Они используются для решения множества задач, таких как логирование, кеширование, проверка прав доступа и других. Важно понимать основы работы с декораторами, чтобы эффективно использовать их в своих проектах. Освоив принципы работы с декораторами, вы сможете значительно улучшить структуру своего кода и упростить его поддержку. ��

Декораторы в Python: понять и полюбить

Декораторы в Python — полезная вещь, но многие новички её не понимают и обходят стороной. Объясняем, что они из себя представляют и как работают.

Обложка поста Декораторы в Python: понять и полюбить

Декораторы — один из самых полезных инструментов в Python, однако новичкам они могут показаться непонятными. Возможно, вы уже встречались с ними, например, при работе с Flask, но не хотели особо вникать в суть их работы. Эта статья поможет вам понять, чем являются декораторы и как они работают.

Что такое декоратор?

Новичкам декораторы могут показаться неудобными и непонятными, потому что они выходят за рамки «обычного» процедурного программирования как в Си, где вы объявляете функции, содержащие блоки кода, и вызываете их. То же касается и объектно-ориентированного программирования, где вы определяете классы и создаёте на их основе объекты. Декораторы не принадлежат ни одной из этих парадигм и исходят из области функционального программирования. Однако не будем забегать вперёд, разберёмся со всем по порядку.

Декоратор — это функция, которая позволяет обернуть другую функцию для расширения её функциональности без непосредственного изменения её кода. Вот почему декораторы можно рассматривать как практику метапрограммирования, когда программы могут работать с другими программами как со своими данными. Чтобы понять, как это работает, сначала разберёмся в работе функций в Python.

Как работают функции

Все мы знаем, что такое функции, не так ли? Не будьте столь уверены в этом. У функций Python есть определённые аспекты, с которыми мы нечасто имеем дело, и, как следствие, они забываются. Давайте проясним, что такое функции и как они представлены в Python.

Функции как процедуры

С этим аспектом функций мы знакомы лучше всего. Процедура — это именованная последовательность вычислительных шагов. Любую процедуру можно вызвать в любом месте программы, в том числе внутри другой процедуры или даже самой себя. По этой части больше нечего сказать, поэтому переходим к следующему аспекту функций в Python.

Функции как объекты первого класса

В Python всё является объектом, а не только объекты, которые вы создаёте из классов. В этом смысле он (Python) полностью соответствует идеям объектно-ориентированного программирования. Это значит, что в Python всё это — объекты:

  • числа;
  • строки;
  • классы (да, даже классы!);
  • функции (то, что нас интересует).

Тот факт, что всё является объектами, открывает перед нами множество возможностей. Мы можем сохранять функции в переменные, передавать их в качестве аргументов и возвращать из других функций. Можно даже определить одну функцию внутри другой. Иными словами, функции — это объекты первого класса. Из определения в Википедии:

Объектами первого класса в контексте конкретного языка программирования называются элементы, с которыми можно делать всё то же, что и с любым другим объектом: передавать как параметр, возвращать из функции и присваивать переменной.

И тут в дело вступает функциональное программирование, а вместе с ним — декораторы.

Функциональное программирование — функции высших порядков

В Python используются некоторые концепции из функциональных языков вроде Haskell и OCaml. Пропустим формальное определение функционального языка и перейдём к двум его характеристикам, свойственным Python:

  • функции являются объектами первого класса;
  • следовательно, язык поддерживает функции высших порядков.

Функциональному программированию присущи и другие свойства вроде отсутствия побочных эффектов, но мы здесь не за этим. Лучше сконцентрируемся на другом — функциях высших порядков. Что есть функция высшего порядка? Снова обратимся к Википедии:

Функции высших порядков — это такие функции, которые могут принимать в качестве аргументов и возвращать другие функции.

Если вы знакомы с основами высшей математики, то вы уже знаете некоторые математические функции высших порядков порядка вроде дифференциального оператора d/dx. Он принимает на входе функцию и возвращает другую функцию, производную от исходной. Функции высших порядков в программировании работают точно так же — они либо принимают функцию(и) на входе и/или возвращают функцию(и).

Пара примеров

Раз уж мы ознакомились со всеми аспектами функций в Python, давайте продемонстрируем их в коде:

def hello_world(): print('Hello world!') 

Здесь мы определили простую функцию. Из фрагмента кода далее вы увидите, что эта функция, как и классы с числами, является объектом в Python:

>>> def hello_world(): . print('Hello world!') . >>> type(hello_world) >>> class Hello: . pass . >>> type(Hello) >>> type(10)

Как вы заметили, функция hello_world принадлежит типу . Это означает, что она является объектом класса function . Кроме того, класс, который мы определили, принадлежит классу type . От этого всего голова может пойти кругом, но чуть поигравшись с функцией type вы со всем разберётесь.

Теперь давайте посмотрим на функции в качестве объектов первого класса.

Мы можем хранить функции в переменных:

>>> hello = hello_world >>> hello() Hello world! 

Определять функции внутри других функций:

>>> def wrapper_function(): . def hello_world(): . print('Hello world!') . hello_world() . >>> wrapper_function() Hello world! 

Передавать функции в качестве аргументов и возвращать их из других функций:

>>> def higher_order(func): . print('Получена функция <> в качестве аргумента'.format(func)) . func() . return func . >>> higher_order(hello_world) Получена функция в качестве аргумента Hello world!

Из этих примеров должно стать понятно, насколько функции в Python гибкие. С учётом этого можно переходить к обсуждению декораторов.

Как работают декораторы

Повторим определение декоратора:

Декоратор — это функция, которая позволяет обернуть другую функцию для расширения её функциональности без непосредственного изменения её кода.

Раз мы знаем, как работают функции высших порядков, теперь мы можем понять как работают декораторы. Сначала посмотрим на пример декоратора:

def decorator_function(func): def wrapper(): print('Функция-обёртка!') print('Оборачиваемая функция: <>'.format(func)) print('Выполняем обёрнутую функцию. ') func() print('Выходим из обёртки') return wrapper 

Здесь decorator_function() является функцией-декоратором. Как вы могли заметить, она является функцией высшего порядка, так как принимает функцию в качестве аргумента, а также возвращает функцию. Внутри decorator_function() мы определили другую функцию, обёртку, так сказать, которая обёртывает функцию-аргумент и затем изменяет её поведение. Декоратор возвращает эту обёртку. Теперь посмотрим на декоратор в действии:

>>> @decorator_function . def hello_world(): . print('Hello world!') . >>> hello_world() Оборачиваемая функция: Выполняем обёрнутую функцию. Hello world! Выходим из обёртки 

Магия, не иначе! Просто добавив @decorator_function перед определением функции hello_world() , мы модифицировали её поведение. Однако как вы уже могли догадаться, выражение с @ является всего лишь синтаксическим сахаром для hello_world = decorator_function(hello_world) .

Иными словами, выражение @decorator_function вызывает decorator_function() с hello_world в качестве аргумента и присваивает имени hello_world возвращаемую функцию.

И хотя этот декоратор мог вызвать вау-эффект, он не очень полезный. Давайте взглянем на другие, более полезные (наверное):

def benchmark(func): import time def wrapper(): start = time.time() func() end = time.time() print('[*] Время выполнения: <> секунд.'.format(end-start)) return wrapper @benchmark def fetch_webpage(): import requests webpage = requests.get('https://google.com') fetch_webpage() 

Здесь мы создаём декоратор, замеряющий время выполнения функции. Далее мы используем его на функции, которая делает GET-запрос к главной странице Google. Чтобы измерить скорость, мы сначала сохраняем время перед выполнением обёрнутой функции, выполняем её, снова сохраняем текущее время и вычитаем из него начальное.

После выполнения кода получаем примерно такой результат:

[*] Время выполнения: 1.4475083351135254 секунд. 

К этому моменту вы, наверное, начали осознавать, насколько полезными могут быть декораторы. Они расширяют возможности функции без редактирования её кода и являются гибким инструментом для изменения чего угодно.

Используем аргументы и возвращаем значения

В приведённых выше примерах декораторы ничего не принимали и не возвращали. Модифицируем наш декоратор для измерения времени выполнения:

def benchmark(func): import time def wrapper(*args, **kwargs): start = time.time() return_value = func(*args, **kwargs) end = time.time() print('[*] Время выполнения: <> секунд.'.format(end-start)) return return_value return wrapper @benchmark def fetch_webpage(url): import requests webpage = requests.get(url) return webpage.text webpage = fetch_webpage('https://google.com') print(webpage) 

Вывод после выполнения:

[*] Время выполнения: 1.4475083351135254 секунд.   

Как вы видите, аргументы декорируемой функции передаются функции-обёртке, после чего с ними можно делать что угодно. Можно изменять аргументы и затем передавать их декорируемой функции, а можно оставить их как есть или вовсе забыть про них и передать что-нибудь совсем другое. То же касается возвращаемого из декорируемой функции значения, с ним тоже можно делать что угодно.

Звёздный Python: где и как используются * и **

Декораторы с аргументами

Мы также можем создавать декораторы, которые принимают аргументы. Посмотрим на пример:

def benchmark(iters): def actual_decorator(func): import time def wrapper(*args, **kwargs): total = 0 for i in range(iters): start = time.time() return_value = func(*args, **kwargs) end = time.time() total = total + (end-start) print('[*] Среднее время выполнения: <> секунд.'.format(total/iters)) return return_value return wrapper return actual_decorator @benchmark(iters=10) def fetch_webpage(url): import requests webpage = requests.get(url) return webpage.text webpage = fetch_webpage('https://google.com') print(webpage) 

Здесь мы модифицировали наш старый декоратор таким образом, чтобы он выполнял декорируемую функцию iters раз, а затем выводил среднее время выполнения. Однако чтобы добиться этого, пришлось воспользоваться природой функций в Python.

Функция benchmark() на первый взгляд может показаться декоратором, но на самом деле таковым не является. Это обычная функция, которая принимает аргумент iters , а затем возвращает декоратор. В свою очередь, он декорирует функцию fetch_webpage() . Поэтому мы использовали не выражение @benchmark , а @benchmark(iters=10) — это означает, что тут вызывается функция benchmark() (функция со скобками после неё обозначает вызов функции), после чего она возвращает сам декоратор.

Да, это может быть действительно сложно уместить в голове, поэтому держите правило:

Декоратор принимает функцию в качестве аргумента и возвращает функцию.

В нашем примере benchmark() не удовлетворяет этому условию, так как она не принимает функцию в качестве аргумента. В то время как функция actual_decorator() , которая возвращается benchmark() , является декоратором.

Объекты-декораторы

Напоследок стоит упомянуть, что не только функции, а любые вызываемые объекты могут быть декоратором. Экземпляры классов/объекты с методом __call__() тоже можно вызывать, поэтому их можно использовать в качестве декораторов. Эту функциональность можно использовать для создания декораторов, хранящих какое-то состояние. Например, вот декоратор для мемоизации:

from collections import deque class Memoized: def __init__(self, cache_size=100): self.cache_size = cache_size self.call_args_queue = deque() self.call_args_to_result = <> def __call__(self, fn): def new_func(*args, **kwargs): memoization_key = self._convert_call_arguments_to_hash(args, kwargs) if memoization_key not in self.call_args_to_result: result = fn(*args, **kwargs) self._update_cache_key_with_value(memoization_key, result) self._evict_cache_if_necessary() return self.call_args_to_result[memoization_key] return new_func def _update_cache_key_with_value(self, key, value): self.call_args_to_result[key] = value self.call_args_queue.append(key) def _evict_cache_if_necessary(self): if len(self.call_args_queue) > self.cache_size: oldest_key = self.call_args_queue.popleft() del self.call_args_to_result[oldest_key] @staticmethod def _convert_call_arguments_to_hash(args, kwargs): return hash(str(args) + str(kwargs)) @Memoized(cache_size=5) def get_not_so_random_number_with_max(max_value): import random return random.random() * max_value 

Само собой, этот декоратор нужен в основном в демонстрационных целях, в реальном приложении для подобного кеширования стоит использовать functools.lru_cache.

P.S.

Тут будут перечислены некоторые важные вещи, которые не были затронуты в статье или были затронуты вскользь. Вам может показаться, что они расходятся с тем, что было написано в статье до этого, но на самом деле это не так.

  • Декораторы не обязательно должны быть функциями, это может быть любой вызываемый объект.
  • Декораторы не обязаны возвращать функции, они могут возвращать что угодно. Но обычно мы хотим, чтобы декоратор вернул объект того же типа, что и декорируемый объект. Пример:>>> def decorator(func). return 'sumit'. >>> @decorator. def hello_world(). print('hello world'). >>> hello_world'sumit'
  • Также декораторы могут принимать в качестве аргументов не только функции. Здесь можно почитать об этом подробнее.
  • Необходимость в декораторах может быть неочевидной до написания библиотеки. Поэтому, если декораторы кажутся вам бесполезными, посмотрите на них с точки зрения разработчика библиотеки. Хорошим примером является декоратор представления в Flask.
  • Также стоит обратить внимание на functools.wraps() — функцию, которая помогает сделать декорируемую функцию похожей на исходную, делая такие вещи, как сохранение doctstring исходной функции.

Заключение

Надеемся, эта статья помогла вам понять, какая «магия» лежит в основе работы декораторов.

Следите за новыми постами по любимым темам

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

Декораторы — Python: Функции

В программировании часто возникают задачи, когда нужно добавить поведение к уже существующим функциям или классам. Например, логирование, проверку входных данных или замер времени выполнения функции. В таких случаях использование декораторов может значительно упростить решение задачи.

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

Что такое декораторы

Декораторы позволяют динамически изменять поведение функций и классов с помощью добавления или изменения их функциональности без изменения самого кода.

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

Декораторы используются, чтобы изменять работу существующих функций или классов, добавлять новые возможности и обеспечивать безопасность.

Предположим, что у нас есть функция, которая выполняет математические операции и возвращает результат:

def add_numbers(x, y): return x + y 

Мы можем создать декоратор, который добавит к этой функции функциональность для отладки:

def debug_decorator(func): def wrapper(*args, **kwargs): print("Вызов функции:", func.__name__) print("Аргументы:", args, kwargs) result = func(*args, **kwargs) print("Результат:", result) return result return wrapper 

Этот декоратор принимает функцию в качестве аргумента и возвращает новую функцию-обертку, которая добавляет отладочные сообщения в процесс выполнения исходной функции. Чтобы применить этот декоратор к функции add_numbers , мы можем вызвать эту функцию с аргументом:

@debug_decorator def add_numbers(x, y): return x + y 

Теперь функция add_numbers будет выполняться с дополнительными отладочными сообщениями:

add_numbers(2, 3) # Вызов функции: add_numbers # Аргументы: (2, 3) <> # Результат: 5 

Также мы можем создавать несколько декораторов для одной функции, которые будут применяться последовательно:

@debug_decorator @time_decorator def add_numbers(x, y): return x + y 

В этом примере сначала применится декоратор времени выполнения, а затем отладочный декоратор.

Как связаны декораторы и замыкания

Внутренняя функция wrapper декоратора обычно ссылается на переменные из внешней функции, что создает замыкание. В примере с декоратором debug_decorator функция wrapper ссылается на func , которая была определена во внешней функции debug_decorator . Это позволяет декоратору использовать и изменять переменные из внешней функции в рамках своей логики работы, что делает декораторы более гибкими инструментами.

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

Вот пример декоратора, который использует замыкание, чтобы отслеживать количество вызовов функции:

def count_calls(func): num_calls = 0 def wrapper(*args, **kwargs): nonlocal num_calls num_calls += 1 print(f"Функция была вызвана num_calls> раз(а)") return func(*args, **kwargs) return wrapper @count_calls def my_func(): print("Hello, world!") my_func() # Функция была вызвана 1 раз(а) # Hello, world! my_func() # Функция была вызвана 2 раз(а) # Hello, world! 

В этом примере декоратор count_calls принимает функцию func и возвращает новую функцию wrapper . Последняя отслеживает количество вызовов func и выводит сообщение при каждом вызове. Затем декоратор применяется к функции my_func . Каждый раз, когда my_func вызывается, декоратор увеличивает счетчик вызовов и выводит сообщение.

Рассмотрим еще один пример, где создадим декоратор, который измеряет время выполнения функции:

import time def timer(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"Время выполнения функции func.__name__>: end_time - start_time> сек.") return result return wrapper @timer def some_function(): time.sleep(2) some_function() # Время выполнения функции some_function: 2.000108242034912 сек. 

Здесь мы определяем декоратор timer , который принимает функцию func и возвращает функцию-обертку wrapper . Функция-обертка вызывает функцию func , замеряет время ее выполнения и сохраняет результат работы func в переменную result . Затем функция-обертка выводит время выполнения функции на экран и возвращает результат вызова функции.

В конце применяем декоратор timer к функции some_function . Когда мы вызываем функцию some_function , декоратор автоматически вызывается и выводит время выполнения функции на экран.

Выводы

Существует большое количество готовых декораторов, доступных в стандартной библиотеке Python и других библиотеках. Некоторые из них позволяют кэшировать результаты функций, обеспечивать авторизацию и безопасность, профилировать код, проверять типы данных и многое другое.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Декораторы в Python

Декоратор — это функция, которая принимает в качестве аргумента другую (оригинальную) функцию и изменяет ее поведение, не изменяя саму функцию. Возвращает другую функцию — замыкание.

  • Замыкание обычно принимает любой набор позиционных и именованных аргументов.
  • Замыкание вызывает оригинальную функцию с помощью переданных аргументов и возвращает результат в декоратор.

Пример декоратора

Для начала определим функцию net_price :

def net_price(price, tax): """ подсчитывает стоимость интернета исходя из цены и налога Аргументы: price: цена интернета tax: налог на добавленную стоимость или налог с продаж Возвращает стоимость интернета """ return price * (1 + tax) 

Функция net_price рассчитывает итоговую стоимость интернета исходя из цены и налога. Она возвращает число net_price — стоимость интернета.

Предположим, что вам нужно получить стоимость в долларах. Тогда результат 100 нужно отформатировать так: $100. Для этого можно использовать декоратор.

По определению, декоратор — это функция, которая принимает функцию в качестве аргумента:

def currency(fn): pass

И возвращает другую функцию:

def currency(fn): def wrapper(*args, **kwargs): fn(*args, **kwargs) return wrapper

Здесь функция currency() возвращает функцию wrapper() . У wrapper() следующие параметры: *args , **kwargs .

Эти параметры позволяют вызывать произволную функцию fn() с любым набором позиционных и именованных аргументов.

В этом примере функция wrapper() , по сути, напрямую выполняет функцию fn() , но не изменяет ее поведение.

Внутри функциия wrapper() вы можете вызвать fn() , получить ее результат и отформатировать результат.

Например, таким образом можно добавить знак валюты.

def currency(fn): def wrapper(*args, **kwargs): result = fn(*args, **kwargs) return f'$' return wrapper

Функция currency() — декоратор.

currency() принимает в качестве аргумента любую другую функцию и возвращает результат этой функции со знаком $ перед ним.

Чтобы использовать декоратор currency() , нужно передать функцию net_price , чтобы получить новую функцию и выполнть ее, как если бы это была исходная функция. То есть сделать вот так:

net_price = currency(net_price) print(net_price(100, 0.05)) # Вывод: $105.0

Символ @

В предыдущем примере функция currency() — декоратор. С ее помощью вы можете декорировать функцию net_price следующим образом:

net_price = currency(net_price)

Общий синтаксис такой:

функция = декоратор(функция)

В Python есть более короткий способ декорирования — с помощью символа @ :

@декоратор
def функция():
тело функции

То есть вместо того чтобы писать так:

net_price = currency(net_price) 

функцию net_price можно декорировать с помощью currency при создании следующим образом:

@currency def net_price(price, tax): """ подсчитывает стоимость интернета исходя из цены и налога Аргументы: price: цена интернета tax: налог на добавленную стоимость или налог с продаж Возвращает стоимость интернета """ return price * (1 + tax) 

Если все соединить вместе, получится такой код:

# декоратор def currency(fn): def wrapper(*args, **kwargs): result = fn(*args, **kwargs) return f'$' return wrapper # декорируемая функция @currency def net_price(price, tax): """ подсчитывает стоимость интернета исходя из цены и налога Аргументы: price: цена интернета tax: налог на добавленную стоимость или налог с продаж Возвращает стоимость интернета """ return price * (1 + tax) print(net_price(100, 0.05))

Документация декорируемых функций

Функция-декоратор возвращает новую функцию — функцию-обертку (wrapper).

Если вы воспользуетесь встроенной функци help() для вывода документации новых функций, вы не увидите документации для оригинальной функции. Например:

help(net_price) 

Вывод

wrapper(*args, **kwargs)
None

А если вы попытаесь вывести свойство __name__ новой функции, Python вернет имя внутренней функции, которую возвращает декоратор:

print(net_price.__name__)

Вывод

wrapper

Что это значит? Когда вы декорируете функцию, вы теряете сигнатуру и документацию оригинальной функции.

Чтобы исправить это, можэно использовать функцию wraps() из стандартного модуля functools . На самом деле wraps — тоже декоратор.

Вот, как использовать декоратор wraps :

from functools import wraps def currency(fn): @wraps(fn) def wrapper(*args, **kwargs): result = fn(*args, **kwargs) return f'$' return wrapper @currency def net_price(price, tax): """ подсчитывает стоимость интернета исходя из цены и налога Аргументы: price: цена интернета tax: налог на добавленную стоимость или налог с продаж Возвращает стоимость интернета """ return price * (1 + tax) help(net_price) print(net_price.__name__) 

Вывод

net_price(price, tax) подсчитывает стоимость интернета исходя из цены и налога 
Аргументы:
price: цена интернета
tax: налог на добавленную стоимость или налог с продаж
Возвращает
стоимость интернета
net_price

Что нужно запомнить

  • Декоратор — это функция, которая принимает в качестве аргумента другую функцию и изменяет ее поведение, не изменяя саму функцию
  • Для декорирования функция можно использовать символ @ .
  • Чтобы сохранить документацию и название исходной функции используйте функцию wraps() из встроенного модуля functools .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *