2023-06-03
604

Функции и декораторы в Python

Объявление функции

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

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

Пример
def func ():
  тело функции

def func (a1, a2, a3=2):
  тело функции

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

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

В списке параметров функции, параметры с дефолтными значениями должны идти в конце.

Возврат значений из функции

return используется для возврата значений, функция может не возвращать что либо, а так же может возвращать несколько аргументов, если return нет, то возвращает всегда None.
Пример возврата нескольких аргументов:
return a1, a2, a3
Прием аргументов из функции
a1, a2, a3 = func()

Аргументы

Порядок расстановки принимаемых аргументов следующий:
([1] обязательные, [2] не обязательные, [3] *args, [4] **kwargs)
*args может перемещаться на более ранние позиции, при этом при вызове функции необходимо однозначно указывать имена аргументов.

*args — позиционные аргументы, все позиционные аргументы будут переданы как tuple. Используется, когда неизвестно, какое количество аргументов будет передано в функцию

def func(*args) - в agrs будет кортеж параметров, в нее можно передать список таким образом, после *args могут идти обычные параметры.
func (*list_in) - * это распаковка, набор выводится поэлементно.

  • * - является определением того, что аргументы позиционные;
  • **kwargs - произвольные именованные аргументы, все произвольные именованные аргументы будут переданы как dict;
  • ** - является определением того, что аргументы произвольные именованные.
Пример
def func (**kwargs):
  тело функции

func (a1=True, a2=5)  # именованные переменные, если указать просто значения без имени, будет ошибка

Анонимные функции (lambda)

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

    Особенности:
  • Выполняется быстрее;
  • Могут содержать лишь одно выражение;
  • Могут не присваиваться какой либо переменной;
  • Возвращают лишь один объект;
  • Не требуется инструкция return;
  • В остальном поведение как у обычной функции.
Шаблон
[name = ]lambda args: return_value
  • [name = ] - необязательное имя
  • lambda - зарезервированное слово
  • args - набор принимаемых аргументов
  • return_value - инструкции и возвращаемый результат
Пример
func = lambda x,y: x + y             # объявление
print(func(10,20))                   # вызов
print((lambda x, y: x + y)(10, 20))  # и объявление и вызов

Декораторы

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

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

Функцию нужно всегда вызывать через декоратор, если он добавлен.

Пример
def my_decorator(func):
  def wrapper():
    print('Start')
    out = func()
    print('End')
    return out
  return wrapper

# вызов, оборачивает функцию и возвращает обернутую функцию которую можно вызвать
wrap1 = my_decorator(my_fn) 
wrap1()
или можно указать, чтоб функции вызывались сразу, по умолчанию, с декораторами
@my_decorator
  def my_fn():
    print('123')
  
# вызов, функция сразу вызывается с декоратором
my_fn()
Пример декоратора с передачей параметров
def decorator_send_arg(func):
  def wrapper(a, b):
    print(f'receive {a} and {b}')
    out = func(a, b)
    return out
  return wrapper

@decorator_send_arg
def print_full_name(first_name, last_name):
  print(f'My name {first_name}, my surname {last_name}')

print_full_name('name1','name2')
Декоратор получающий аргументы
def decorator_with_arg(dec_a, dec_b):
  print(f'{dec_a} and {dec_b}')

def my_decorator(func):
  print(f'{dec_a} and {dec_b}')

def wrapped(func_a, func_b):
  print(f'wrapped. Have access {dec_a}, {dec_b}, {func_a}, {func_b}')
  return func(func_a, func_b)
  return wrapped

return my_decorator

@decorator_with_arg('Decorator','cool')
def decorated_fucnction_with_arg(arg1, arg2):
  print(arg1, arg2)

decorated_fucnction_with_arg('Yes','of course')