Содержание
1. Что такое функции?
2. Что такое замыкание?
3. Декораторы
4. Реальный пример
5. Декораторы, принимающие аргументы
Прежде чем иметь дело с декораторами, важны две другие концепции Python: функции и замыкание.
1. Что такое функции?
Функции такие же, как и любой другой тип данных, в том смысле, например, что вы можете присвоить его переменной, а затем вызвать эту переменную (вызов функции). Вы также можете передать одну функцию другой или даже вернуть функцию из функции.
def funct(): print('Hi!') x = funct x() #Prints 'Hi!'
2. Что такое закрытие?
Закрытие — это способ убедиться, что функция имеет параметры, необходимые для запуска. Это кортеж переменных, которые больше не доступны в области видимости.
def funct(x): a = 5 def inner_funct(x): print(a) return inner_funct call_func = funct() # Assigns to inner_funct call_func() # Prints 5
Как объяснить, что inner_funct (call_func) запоминает значение a, если оно было определено во внешней функции? Когда func возвращает функцию inner_funct, она прикрепляет все, что функция использует, к объекту функции. Вы можете получить доступ к этим значениям следующим образом:
type(call_func.__closure__) # A tuple print(call_func.__closure__[0].cell_contents) # Access the actual value
3. Декораторы
Декораторы — это просто функции, которые принимают одну функцию в качестве аргумента и возвращают модифицированную версию этой функции. Для начала давайте разберемся с функцией, которая получает в качестве аргумента другую и возвращает функцию.
def mult(a, b): prints(a * b) def dec_funct(func): def wrapper(a, b): return mult(a * 2, b * 2) return wrapper new_mult = dec_funct(mult) new_mult(1, 5) # Prints 20
Анализируя код выше, мы имеем следующее: во-первых, у нас есть функция mult, которая будет оформлена. Эта функция просто умножает два числа, переданные в качестве аргументов.
Позже у нас есть dec_funct, который работает как наш декоратор. Он берет функцию, модифицирует ее и возвращает другую. Чтобы иметь возможность возвращать функцию, внутри создается новая функция: функция-оболочка. Функция-оболочка возвращает функцию, оформленную (mult) с небольшим изменением (удвоением аргументов).
Когда new_mult назначается dec_funt(mult), объект теперь является функцией, которая умножает параметры на два, а затем умножает их. Вызов new_mult(1, 5) вызывает измененную версию функции mult. Вместо new_mult мы можем просто переопределить mult без каких-либо проблем, потому что определение функции хранится в замыкании новой функции.
mult = dec_funct(mult) mult(1, 5) # Prints 20
Код, построенный на данный момент, эквивалентен приведенному ниже коду с использованием соответствующего синтаксиса для декораторов:
def dec_funct(func): def wrapper(a, b): return mult(a * 2, b * 2) return wrapper @dec_funct def mult(a, b): prints(a * b) mult(1, 5) # Prints 20
Декорирование функции аналогично вызову функции-декоратора с декорированной функцией в качестве аргумента и присвоению ее самой себе.
4. Реальный пример
Декоратор ниже умножает, сколько нужно, чтобы суммировать от 1 до 100 000.
import time def timer(func): def wrapper(*args, **kwargs): # Arguments to work with any function t_start = time.time() result = func(*args, **kwargs) t_total = time.time() - t_start print(f'The total time for running was {t_total:.2}.') return result return wrapper @timer def count(): for i in range(1, 100000): i += 1 count()
5. Декораторы, принимающие аргументы
Декоратор, принимающий аргументы, — это функция, возвращающая декоратор, а не функция, которая является единицей.
def run_n_times(n): # Returns a decorator def decorator(func): # Decorator function def wrapper(*args, **kwargs): for i in range(n): func(*args, **kwargs) return wrapper return decorator @run_n_times(5) # Runs the function 5 times def prints(): print('Printing')
Он устроен таким образом, что функция оболочки имеет доступ к переменной, переданной в run_n_times(n). При вызове @run_n_times(5) мы украшаем функцию prints результатом этого вызова (декоратором функции).
______________
Это мои учебные записи. Я надеюсь, что это может быть полезно для вас, но остерегайтесь любых ошибок, которые вы можете совершить.
Давайте подключимся к LinkedIn!