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


Декораторите в Python позволяват на програмистите да променят поведението на функцията, без действително да я променят. Преди да преминем към декораторите, първо трябва да разберем тези неща:

  • как работят вложените функции и
  • как да предавам функция като аргумент на друга функция.

Вложена функция в Python

Вложената функция в python е функция, присъстваща в друга функция.

def outer_function():
  def inner_function():
    print("Inside the inner function")
  return inner_function

inner_function=outer_function()
print(type(inner_function))
inner_function()

Имаме функция, наречена external_function, която не приема никакви параметри. Вътре във външната_функция дефинирахме друга функция, наречена вътрешна_функция, която има прост оператор за печат. Когато се извика, външната_функция връща вътрешната_функция.

Записваме върнатата стойност в променлива и типът на върнатата стойност е функция. За да изпълним вътрешната_функция, ние я извикваме.

Предаване на функция като аргумент в Python

Можем да предадем функция като аргумент на други функции. Нека модифицираме самата програма по-горе.

def inner_function():
  print("Inside the inner function")

def outer_function(func):
    func()

outer_function(inner_function)

Предаваме вътрешна_функция на външна_функция като аргумент и извикваме вътрешната_функция вътре външната_функция.

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

Сега ще видим как можем да създадем декоратори в python. Тъй като сме покрили предпоставките, нека да създадем прост декоратор.

def function_to_be_called():
  print("This is the main function")

def decorator_function(func):
  def inner():
    print("Before execution of the function")
    func()
    print("After execution of the function")
  return inner

function_to_be_called=decorator_function(function_to_be_called)  
function_to_be_called()

Нашата функция decorator_ Функция приема функция като аргумент, така че ние създаваме нова функция, наречена function_to_be-извикана и предадена на decorator_function.

In Питон, можем да приложим декоратор към функция, като поставим символ @ преди функцията, която искаме да декорираме. Горният код може да бъде модифициран като

def decorator_function(func):
  def inner():
    print("Before execution of the function")
    func()
    print("After execution of the function")
  return inner

@decorator_function
def function_to_be_called():
  print("This is the main function")
  
function_to_be_called()

В горния пример обърнете внимание, че декораторите в python разширяват функционалността на функцията “function_to_be_called”, без да променят нейния изходен код.

Какво е functools.wraps ()

Нека да видим пример, за да разберем необходимостта от functools.wraps ().

def decorator_function(func):
  def inner():
    '''This function extends the function be called'''
    print("Before execution of the function")
    func()
    print("After execution of the function")
  return inner

@decorator_function
def first_function():
  print("This is the fisrt function")

@decorator_function
def second_function():
  print("This is the second function")
  
print(first_function.__name__)
print(first_function.__doc__)
print(second_function.__name__)
print(second_function.__doc__)

Когато отпечатвате името и документацията на първата_функция и втората_функция, тя отпечатва името и документацията на вътрешната функция, вместо да показва името и документацията на първата_функция и втората_функция. Това ще бъде по-объркващо, ако повече функции използват вътрешната функция.

Едно решение ще бъде ръчното присвояване на името и документацията, както по-долу:

def decorator_function(func):
  def inner():
    '''This function extends the function be called'''
    print("Before execution of the function")
    func()
    print("After execution of the function")
  #manually assigning name and docstrings
  inner.__name__=func.__name__  
  inner.__doc__=func.__doc__  
  return inner

@decorator_function
def first_function():
  '''Docstring for 1st function'''
  print("This is the fisrt function")

@decorator_function
def second_function():
  '''Docstring for 2nd function'''
  print("This is the second function")
  
print(first_function.__name__)
print(first_function.__doc__)
print(second_function.__name__)
print(second_function.__doc__)

Сега се отпечатва правилно.

Ако използваме повече декоратори в python, трябва да напишем тези редове за всеки от тях. Следователно най-ефективният начин е да използвате functools.wraps като декоратор на вътрешната функция, за да спестите време, както и да увеличите четливостта.

from functools import wraps

def decorator_function(func):
  @wraps(func)
  def inner():
    '''This function extends the function be called'''
    print("Before execution of the function")
    func()
    print("After execution of the function")
  return inner

@decorator_function
def first_function():
  '''Docstring for 1st function'''
  print("This is the fisrt function")

@decorator_function
def second_function():
  '''Docstring for 2nd function'''
  print("This is the second function")
  
print(first_function.__name__)
print(first_function.__doc__)
print(second_function.__name__)
print(second_function.__doc__)

Множество декоратори в Python

Можем да приложим множество декоратори към функция. Редът на приложението на декоратори ще бъде отдолу нагоре.

from functools import wraps
def uppercase_convertor(func):
  @wraps(func)
  def wrapper():
    var=func()
    return var.upper()
  return wrapper

def split_string(func):
  @wraps(func)
  def wrapper():
    var=func()
    return var.split()
  return wrapper

@split_string
@uppercase_convertor
def sample_function():
  return 'Hello world'

output=sample_function()
print(output)

Функцията sample_function има два декоратора. Първо, горният регистър_конвертор се извиква и функцията за главни букви ще бъде предадена като аргумент на функцията split_string.

Също така можем да предаваме аргументи на декораторите в python точно както предаваме аргументи на нормалната функция.

заключение

Прочетохме за декоратори в Python и множество декоратори в Python. Също така разгледахме вложени функции в Python и как да предадем функция като аргумент на друга функция в Python.

препратка