Python 3 def: Python 3 — Functions — Tutorialspoint

Содержание

Функции Python 3: значение, аргументы, вызов, переменные, списки — Python 3 | Data Science | Нейронные сети | AI

Содержание страницы

Функции – главный и самый важный способ организации и повторного использования кода в Python. Функций не может быть слишком много. 1 функция — это блок кода, который используется для выполнения одного связанного действия.

В Python есть два инструмента для создания функций: def и lambda.

Сначала рассмотрим def. К lambda функции вернемся позже.

Python предоставляет вам множество встроенных функций, таких как print() и т.д., но вы также можете создавать свои собственные функции. Эти функции называются пользовательскими функциями.

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

def my_function(x, y, z=1.5):
    if z > 1:
        return z * (x + y)
    else:
        return z / (x + y)

Ничто не мешает иметь в функции несколько предложений return. Если при выполнении достигнут конец функции, а предложение return не встретилось, то возвращается None.

У функции могут быть позиционные и именованные аргументы.

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

В примере выше:

  • x и y – позиционные аргументы,
  • а z – именованный.

Следующие вызовы функции эквивалентны:

my_function(5, 6, z=0.7)
my_function(3.14, 7, 3.5)

Основное ограничение состоит в том, именованные аргументы должны находиться после всех позиционных (если таковые имеются).

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

Определение функции Python 3

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

  • Ключевое слово для определения функции: def, за которым следуют имя функции и круглые скобки () с параметрами.
  • Любые входные параметры или аргументы должны быть помещены в эти круглые скобки.
  • В качестве первой команды может быть необязательная конструкция — строка документации функции (эта часть функции — пояснение зачем функция создана, очень рекомендуется использовать для облегчения понимания кода при работе в команде или при повторном возвращении к коду через длительный промежуток времени).
  • Блок кода в каждой функции начинается с двоеточия
    :
    и имеет отступ.
  • Оператор return [выражение] возвращает результат из функции. Оператор return без аргументов аналогичен return None. Функции всегда возвращают значение, хотя бы None.

Синтаксис функции Python
def function_name( parameter1, parameter2 ):
   """function_docstring: функция Python предназначена для расчета ROI"""
   function_suite (algorithms, expressions)
   return [expression]

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

Пример реализации функции

Следующая функция принимает строку в качестве входного параметра и печатает ее на стандартном экране.

def print_me( str ):
   """Выводит на печать переданную строку в эту функцию"""
   print(str)
   return

Вызов функции

В определении функции указывается имя функции, её параметры, а также тело функции (реализация требуемой функциональности).

Как только базовая структура функции создана, вы можете выполнить ее, вызвав ее из другой функции или непосредственно из Python prompt (командной оболочки). Ниже приведен пример вызова функции printme():

# Определение функции
def printme( str ):
    """This prints a passed string into this function"""
    print(str)
    return

# Теперь вы можете вызвать функцию printme
printme("I'm first call to user defined function!")
printme("Again second call to the same function")

Результат:

I'm first call to user defined function!
Again second call to the same function

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

  • Обязательные аргументы
  • Ключевые аргументы
  • Аргументы по умолчанию
  • Аргументы переменной длины

Обязательные (позиционные) аргументы

Позиционные аргументы: указываются простым перечислением

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

Чтобы вызвать функцию printme() , вам обязательно нужно передать один аргумент, иначе она выдаст следующую синтаксическую ошибку:

# Определение функции
def printme( str ):
   """This prints a passed string into this function"""
   print(str)
   return

# Теперь вы можете вызвать функцию printme
printme()

Ошибка (в функции Printme не указан аргумент):

Traceback (most recent call last):
  File "C:/Users/User/Desktop/CodePythonFunc.py", line 8, in <module>
    printme()
TypeError: printme() missing 1 required positional argument: 'str'

Правильно указать аргумент так:

# Определение функции
def printme( str ):
   """This prints a passed string into this function"""
   print(str)
   return

# Теперь вы можете вызвать функцию printme
printme("Текстовая переменная")

Ключевые аргументы

Ключевые аргументы: указываются перечислением ключ=значение

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

Это позволяет пропускать аргументы или размещать их не по порядку, поскольку интерпретатор Python может использовать предоставленные ключевые слова (ключи) для сопоставления значений с параметрами. Создадим ключевые слова для функции

printinfo() следующими способами:

# Определение функции
def printinfo( name, age ):
   "This prints a passed info into this function"
   print("Name: " + name + "|Age: " + str(age))
   return

# Вызов функции printinfo
printinfo( age=23, name="Anton" )
printinfo( name="Alena", age=20 )

Результат:

Name: Anton|Age: 23
Name: Alena|Age: 20

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

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

Аргументы по умолчанию

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

Следующий пример дает представление об аргументах по умолчанию, он печатает возраст по умолчанию, если он не был передан:

# Определение функции
def printinfo( name, age = 35 ):
   "This prints a passed info into this function"
   print("Name: " + name + "|Age: " + str(age))
   return

# Вызов функции printinfo
printinfo( age=19, name="Семен" )
printinfo( name="Николай" )

Результат:

Name: Семен|Age: 19
Name: Николай|Age: 35

Аргументы переменной длины

Передача кортежа в функцию — Использование *args в Python

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

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

В Python форма с одной звездочкой *argsможет использоваться в качестве параметра для отправки в список функций аргументов переменной длины без ключа. Стоит отметить, что звёздочка ( *) является здесь важным элементом, так как слово argsявляется общепринятой традиционной идиомой, хотя оно не поддерживается языком.

Синтаксис для функции с аргументами переменной длины следующий:

def function_name([formal_args,] *args_tuple ):
    """function_docstring"""
    function_body
    return [expression]

Звездочка (*) ставится перед именем переменной, которая содержит в себе кортеж значений без ключевых слов. Кортеж является необязательным параметром.

Рассмотрим простой пример:

# Определение функции def print_info( parametr_1, *var_tuple ): """Эта функция производит вывод переданных аргументов""" print("Output is: ") print(parametr_1) for elem in var_tuple: print(elem) return # Вызов функции printinfo print_info( 10 ) print_info( 70, 60, 50 )

Результат:

Output is: 
10
Output is: 
70
60
50

Еще один пример использования *args в функции Python:

def multiply(*args):
    z = 1
    for num in args:
        z *= num
    print(z)

multiply(4, 5)
multiply(10, 9)
multiply(2, 3, 4)
multiply(3, 5, 10, 6)

Результат:

20
90
24
900

Поскольку мы использовали *argsдля отправки списка аргументов переменной длины в нашу функцию, мы смогли передать столько аргументов, сколько пожелали, в вызовы функции.

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

Передачи словаря переменной длины с аргументами в функцию **kwargs

**kwargs — сокращение от “keyword arguments”

Форма двойной звездочки **kwargsиспользуется для передачи словарного словаря с аргументами переменной длины в функцию. Опять же, две звездочки ( **) являются здесь важным элементом, так как слово kwargsиспользуется условно, но не поддерживается языком.

Мол *args**kwargsможет принять столько аргументов, которые вы хотели бы привести к этому. Однако **kwargsотличается от того, *argsчто вам нужно будет назначить ключевые слова.

Во-первых, давайте просто распечатаем **kwargsаргументы, которые мы передаем функции. Мы создадим короткую функцию для этого:

def print_kwargs(**kwargs):
        print(kwargs)

print_kwargs(kwargs_1="Shark", kwargs_2=4.5, kwargs_3=True)

Давайте запустим программу выше и посмотрим на вывод:

{'kwargs_1': 'Shark', 'kwargs_2': 4.5, 'kwargs_3': True}

В зависимости от версии Python 3, которую вы используете в данный момент, тип данных словаря может быть неупорядоченным. В Python 3.6 и выше вы получите пары ключ-значение по порядку, но в более ранних версиях пары будут выводиться в случайном порядке.

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

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

def print_values(**kwargs):
    for key, value in kwargs. items():
        print("The value of {} is {}".format(key, value))

print_values(my_name="Sammy", your_name="Casey")

Результат:

The value of my_name is Sammy
The value of your_name is Casey

Использование **kwargsдает нам гибкость в использовании ключевых аргументов в нашей программе. Когда мы используем **kwargsв качестве параметра, нам не нужно знать, сколько аргументов мы в конечном итоге хотели бы передать функции.

Использование *args и **kwargs в вызовах функций

Мы также можем использовать *argsи **kwargsдля передачи аргументов в функции.

Сначала давайте рассмотрим пример с *args.

def some_args(arg_1, arg_2, arg_3):
    print("arg_1:", arg_1)
    print("arg_2:", arg_2)
    print("arg_3:", arg_3)

args = ("Sammy", "Casey", "Alex")
some_args(*args)

В функции выше, существует три параметра , определенный как arg_1arg_и arg_3. Функция распечатает каждый из этих аргументов. Затем мы создаем переменную, для которой задано итеративное значение (в данном случае кортеж ), и можем передать эту переменную в функцию с синтаксисом звездочки.

Когда мы запустим код, мы получим следующий вывод:

arg_1: Sammy
arg_2: Casey
arg_3: Alex

Мы также можем изменить вышеприведенную программу для типа данных итеративного списка с другим именем переменной. Давайте также объединим *argsсинтаксис с именованным параметром:

def some_args(arg_1, arg_2, arg_3):
    print("arg_1:", arg_1)
    print("arg_2:", arg_2)
    print("arg_3:", arg_3)

my_list = [2, 3]
some_args(1, *my_list)

Если мы запустим программу выше, она выдаст следующий вывод:

arg_1: 1
arg_2: 2
arg_3: 3

Аналогично, **kwargsаргументы с ключевым словом могут использоваться для вызова функции.  Мы установим переменную, равную словарю с 3 парами ключ-значение (мы будем использовать kwargsздесь, но она может называться как угодно), и передадим ее функции с 3 аргументами:

def some_kwargs(kwarg_1, kwarg_2, kwarg_3):
    print("kwarg_1:", kwarg_1)
    print("kwarg_2:", kwarg_2)
    print("kwarg_3:", kwarg_3)

kwargs = {"kwarg_1": "Val", "kwarg_2": "Harper", "kwarg_3": "Remy"}
some_kwargs(**kwargs)

Результат:

kwarg_1: Val
kwarg_2: Harper
kwarg_3: Remy

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

Создание функций, которые принимают *argsи **kwargsлучше всего использовать в ситуациях, когда вы ожидаете, что количество входов в списке аргументов останется относительно небольшим. Использование *argsи **kwargsв первую очередь для обеспечения удобочитаемости и удобства, но следует делать с осторожностью.

Комбинирование параметров *args и **kwargs в функции

При комбинировании параметров параметр с двумя звездочками записывается самым последним. Если в определении функции указывается комбинация параметров с одной звездочкой и двумя звездочками, то функция примет любые переданные ей параметры:

def func(*args, **kwargs):
    """Функция примет любые параметры и выведет их на печать"""
    for elem in args:                   # Перебираем список с переданными параметрами
        print(elem, end=" ")
    for key, value in kwargs.items():   # Перебираем словарь с переданными параметрами
        print("{0} => {1}".format(key, value), end=" ")
    print("") #Перенос строки

func(35, 10, a=1, b=2, c=3) # Выведет: 35 10 a => 1 c => 3 b => 2
func(10)                    # Выведет: 10
func(3, a=1, b=2)           # Выведет: a => 1 b => 2

Результат:

35 10 a => 1 b => 2 c => 3 
10 
3 a => 1 b => 2 

Еще один пример использования комбинации *args & **kwargs:

# Описываем функцию
def echo(*args, **kwargs):
    print(args, kwargs)

# Задаем список
args = (10, 20)
# Задаем словарь
kwargs = {'a':30, 'b':40}

#Вызываем функцию
echo(*args, **kwargs)

Результат:

(10, 20) {'a': 30, 'b': 40}

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

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

  1. Позиционные аргументы (arg_1, arg_2)
  2. *args
  3. Ключевые аргументы (kw_1=»значение 1″, kw_2=»значение 2″)
  4. **kwargs

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

def function_print(arg_1, arg_2, *args, kw_1="значение 1", kw_2="значение 2", **kwargs):
    """ Обобщенный пример вывода всех аргументов, переданных функции """
    print("===Позиционные аргументы===")
    print(str(arg_1) + "," + str(arg_2))
    print("===*args===")
    for elem in args: # Перебираем список с переданными параметрами
        print(elem, end=" ")
    print("") #Перенос строки
    print("===Ключевые аргументы===")
    print(kw_1 + "," + kw_2)
    print("===**kwargs===")
    for key, value in kwargs. items(): # Перебираем словарь с переданными параметрами
        print("{0} => {1}".format(key, value), end=" ")
    print("") #Перенос строки


function_print(1, 2, 4, kw_2="Иван", var1=4)

Результат:

===Позиционные аргументы===
1,2
===*args===
4 
===Ключевые аргументы===
значение 1,Иван
===**kwargs===
var1 => 4 

Передача списка (list) по ссылке в функцию
def myfunction (list):
    list.append(40)
    print ("Modified list inside a function: ", list)
    return

mylist=[10,20,30]
myfunction(mylist)
print(mylist)

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

Modified list inside a function: [10, 20, 30, 40]
[10, 20, 30, 40]

Область действия переменной — область видимости переменных

Переменные в программе могут быть доступны или недоступны в разных местах этой программы. Это зависит от того, где вы объявили переменную.

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

  • Глобальные переменные
  • Локальные переменные

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

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

Переменные внутри функции – локальные. Поиск переменных: сперва среди локальных, потом среди глобальных.

Рассмотрим следующую функцию:

def func():
    a = []
    for i in range(5):
        a.append(i)

При вызове func() создается пустой список a, в него добавляется 5 элементов, а затем, когда функция завершается, список a уничтожается. Но допустим, что мы объявили a следующим образом:

a = []
def func():
    for i in range(5):
        a.append(i)

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

a = None

def bind_a_variable():
    global a
    a = []

bind_a_variable()
print a

Результат:

[]

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

def outer_function(x, y, z):
    def inner_function(a, b, c):
        pass
    pass

Здесь функция inner_function не существует, пока не вызвана функция outer_function. Как только outer_function завершает выполнение, inner_function уничтожается.

Не рекомендуется злоупотреблять ключевым словом global. Обычно глобальные переменные служат для хранения состояния системы. Если вы понимаете, что пользуетесь ими слишком часто, то стоит подумать о переходе к объектно-ориентированному программированию (использовать классы).

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

Строго говоря, любая функция локальна в какой-то области видимости, хотя это может быть и область видимости на уровне модуля.

Возврат нескольких значений из одной функции

В Python существует возможность возвращать из функции несколько значений.

Вот простой пример:

def f():
    a = 5
    b = 6
    c = 7
    return a, b, c
var1, var2, var3 = f()

print("var1={0} var2={1} var3={2}".format(var1, var2, var3))

Результат:

var1=5 var2=6 var3=7

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

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

Этот пример можно было бы записать и так:

def f():
    a = 5
    b = 6
    c = 7
    return a, b, c
return_value = f()

print(return_value)

Результат:

(5, 6, 7)

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

Иногда разумнее возвращать несколько значений не в виде кортежа, а в виде словаря:

def f():
    a = 5
    b = 6
    c = 7
    return {'a' : a, 'b' : b, 'c' : c}

return_value = f()

print(return_value)

Результат:

{'a': 5, 'b': 6, 'c': 7}

Функции являются объектами

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

states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', 'FlOrIda', 'south carolina##', 'West virginia?']

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

Первая попытка могла бы выглядеть так:

import re # Модуль регулярных выражений

def clean_strings(strings):
    result = []
    for value in strings:
        value = value.strip()
        value = re.sub('[!#?]', '', value) # удалить знаки препинания
        value = value.title()
        result.append(value)
    return result

states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', 'FlOrIda', 'south carolina##', 'West virginia?']

states = clean_strings(states)

print(states)

Результат:

['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'South Carolina', 'West Virginia']

Другой подход, который иногда бывает полезен, – составить список операций, которые необходимо применить к набору строк:

import re # Модуль регулярных выражений

def remove_punctuation(value):
    return re.sub('[!#?]', '', value)

def clean_strings(strings, ops):
    result = []
    for value in strings:
        for function in ops:
            value = function(value)
        result.append(value)
    return result

clean_ops = [str.strip, remove_punctuation, str.title]
states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', 'FlOrIda', 'south carolina##', 'West virginia?']

states = clean_strings(states, clean_ops)

print(states)

Результат:

['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'South Carolina', 'West Virginia']

Подобный функциональный подход позволяет задать способ модификации строк на очень высоком уровне. Степень повторной используемости функции clean_strings определенно возросла!

Функции можно передавать в качестве аргументов другим функциям, например встроенной функции map, которая применяет переданную функцию к коллекции:

import re # Модуль регулярных выражений

def remove_punctuation(value):
    return re. sub('[!#?]', '', value)

states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', 'FlOrIda', 'south carolina##', 'West virginia?']

states = list(map(remove_punctuation, states))
states = list(map(str.strip, states))
states = list(map(str.title, states))

print(states)

Результат:

['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'South Carolina', 'West Virginia']

Анонимные функции или Лямбда-функции. Lambda Function Python 3
  • Лямбда-функции позволяют создавать «встроенные» функции, которые полезны для функционального программирования. Например, с Map, Filter или Reduce.
  • Lambda — это инструмент для создания обработчиков обратного вызова (callback handlers).

Lambda Function — это анонимная однострочная функция, которая возвращает всегда 1 результат.

Определяются они с помощью ключевого слова lambda

ИмяФункции = lambda переменная_1, переменная_2, …, переменная_N: <выражение, которое использует переменные>

Например, функция equiv_anon:

equiv_anon = lambda x: x * 2

эквивалентна функции short_function:

def short_function(x):
    return x * 2

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

Рассмотрим такой простенький пример:

def apply_to_list(some_list, f):
    return [f(x) for x in some_list]

ints = [4, 0, 1, 5, 6]

result = apply_to_list(ints, lambda x: x * 2)

print(result)

Результат:

[8, 0, 2, 10, 12]

Можно было бы, конечно, написать [x * 2 for x in ints], но в данном случае нам удалось передать функции apply_to_list пользовательский оператор.

Еще пример: пусть требуется отсортировать коллекцию строк по количеству различных букв в строке.

Для этого можно передать лямбда-функцию методу списка sort:

strings = ['foo', 'card', 'bar', 'aaaa', 'abab']

strings.sort(key=lambda x: len(set(list(x))))

print(strings)

Результат:

['aaaa', 'foo', 'abab', 'bar', 'card']

Для чего хороша лямбда-функция? Зачем нужная lambda function в Python?

Ответ:

  • Нам не нужна лямбда функция, мы могли бы обойтись без нее. Но…
  • Есть определенные ситуации, когда это удобно — lambda делает написание кода немного легче, а написанный код — немного чище.

Какие ситуации?

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

Обычно функции создаются для одной из двух целей: (а) для уменьшения дублирования кода или (б) для модульности кода.

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

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

Еще один пример использования lambda функции:

colors = ["Goldenrod", "Purple", "Salmon", "Turquoise", "Cyan"]

normalized_colors = list(map(lambda s: s. casefold(), colors))

print(normalized_colors)

Результат:

['goldenrod', 'purple', 'salmon', 'turquoise', 'cyan']

Неправильное использование: именование лямбда-выражений

PEP8, официальное руководство по стилю Python, советует никогда не писать такой код:

normalize_case = lambda s: s.casefold()

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

Если вы хотите создать однострочную функцию и сохранить ее в переменной, вы должны использовать defвместо этого:

def normalize_case(s): return s.casefold()

PEP8 рекомендует это, потому что именованные функции — это обычная и понятная вещь. Именованная функция также имеет следующее преимущество: назначая нашей функции правильное имя, Вы упрощаете отладку кода. В отличие от функций, определенных с помощью def, лямбда-функции никогда не имеют имени (это всегда <lambda>).

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

Неправильное использование: ненужные вызовы функций

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

Например, возьмем этот код:

sorted_numbers = sorted(numbers, key=lambda n: abs(n))

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

Поскольку abs (которая возвращает абсолютное значение числа) является функцией и все функции могут быть переданы, мы могли бы написать приведенный выше код следующим образом:

sorted_numbers = sorted(numbers, key=abs)

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

pairs = [(4, 11), (8, 8), (5, 7), (11, 3)]
sorted_by_smallest = sorted(pairs, key=lambda items: min(items))

Поскольку мы принимаем те же аргументы, что и при передаче min, нам не нужен этот дополнительный вызов функции. Вместо этого мы можем просто передать min функцию key:

pairs = [(4, 11), (8, 8), (5, 7), (11, 3)]
sorted_by_smallest = sorted(pairs, key=min)

Вам не нужна лямбда-функция, если у вас уже есть другая функция, которая делает то, что вы хотите.

Замыкания: функции, возвращающие функции. Динамически сгенерированная функция

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

Вот очень простой пример:

def make_closure(a):
    def closure():
        print('Я знаю секрет: %d' % a)
    return closure

closure = make_closure(5)
closure()

Результат:

Я знаю секрет: 5

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

Так, в примере выше, возвращенное замыкание печатает строку «Я знаю секрет: 5», в какой бы момент ее ни вызвать. Хотя обычно создают замыкания со статическим внутренним состоянием (в данном случае только значение a), ничто не мешает включить в состав состояния изменяемый объект – словарь, множество, список – и затем модифицировать его.

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

def make_watcher():
    have_seen = {}

    def has_been_seen(x):
        if x in have_seen:
            return True
        else:
            have_seen[x] = True
        return False

    return has_been_seen

watcher = make_watcher()

vals = [5, 6, 1, 5, 1, 6, 3, 5]

print([watcher(x) for x in vals])

Результат:

[False, False, False, True, True, True, False, True]

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

def make_counter():
    count = [0]

    def counter():
        # увеличить счетчик и вернуть новое значение
        count[0] += 1
        return count[0]
    return counter

counter = make_counter()
print(counter())

Результат:

1

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

Вот пример функции форматирования строк:

def format_and_pad(template, space):
    def formatter(x):
        return (template % x).rjust(space)
    return formatter

fmt = format_and_pad('%.4f', 15)
print(fmt(1.756))

Результат:

'         1. 7560'

Каррирование: частичное фиксирование аргументов функции

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

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

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

Мы можем породить на ее основе новую функцию одной переменной, add_five, которая прибавляет к своему аргументу 5:

add_five = lambda y: add_numbers(5, y)

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

Теперь запустим полный код:

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

add_five = lambda y: add_numbers(5, y)

print(add_five(10))

Результат:

15

Стандартный модуль functools упрощает эту процедуру за счет функции partial:

from functools import partial

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

add_five = partial(add_numbers, 5)

print(add_five(10))

Также вернет 15

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

# вычислить скользящее среднее временного ряда x за 60 дней
ma60 = lambda x: pandas.rolling_mean(x, 60)
# вычислить скользящие средние за 60 дней всех временных рядов в data
data.apply(ma60)

5 1 голос

Рейтинг статьи

Навигация по записям

Python functions — Введение в Python

Введение в Python

Видео может быть заблокировано из-за расширений браузера. В статье вы найдете решение этой проблемы.

Functions in Python

Common structure

def name(arg1, ... argN, kwarg1, ... kwargN, *args, **kwargs):
    """Short description
       Long description...
    """
....operator1
....operatorN
....return value

Naming rules

  • lower_underscore_case
  • letters, numbers, underscores
  • leading underscore for private funcs
myFunc()          # bad
My_func           # bad
100_top_users     # SyntaxError
get_top_users()   # ok
_fetch_data()     # perhaps you shouldn't call that directly

Why need docstring

  • Keep code and docs at the same place
  • Useful for IDEs, editors
  • Build documentation from code
  • help(func) or func.doc prints the doc
  • Doctests
def test(a, b, c=3, d=4)

test()                   TypeError
test(1, 2)               a=1, b=2, c=3, d=4
test(4, 10, c=22)        a=4, b=10, c=22, d=4
test(a=6, b=5)           a=6, b=5, c=3, d=4
test(d=4, a=1)           TypeError
test(c=1, b=4, a=5)      a=5, b=4, c=1, d=4
test(9, 8, 7)            a=9, b=8, c=7, d=4
test(9, 8, 7, 6)         a=9, b=8, c=7, d=6

What does function return

- Use return <value> statement
- There might be several return statements
- None if there is no return statement
- Use tuple to return multiple values

def func(foo, bar, baz=42):
    if baz == 42:
        return (False, "some-error")
    else:
        return (True, "OK")

ok, message = func(1, 2)            False, "some-error"
ok, message = func(1, 2, baz=3)     True, "OK"

Function is object

- Copy, delete function
- Pass it into a function call
- Might be either a key or value of a dict
- Has special attrs (__name__, __module__, etc)

def user_auth(user):
    pass

def user_logout(user)
    pass

actions = {"auth": user_auth, "logout": user_logout}

actions[action](user)

args, kwargs

  • def (*args, **kwargs)
  • aggregate rest arguments and keyword arguments
  • args is a tuple, kwargs is a dict
  • useful when you construct arguments step by step
params = {"name": "Ivan", "age": 29}
if . ..
    params["created_at"] = datetime.now()
if ...
    params["friends"] = ["Joe", "Mary"]

create_user(**params)
create_user(name="Ivan", age=29,
                    created_at=datetime.now(),
                    friends=["Joe", "Mary"]
)

Never use mutable defaults!

def test(a=[]):
    a.append(1)
    print a

test()     [1]
test()     [1, 1]
test()     [1, 1, 1]
test()     [1, 1, 1, 1]

Lambdas

  • Came from functional programming
  • A short expression with only one statement inside
  • Pros:
  1. just-in-place function
  2. supports argument unpacking
  1. long ones are ugly
  2. hard to debug
double = lambda x: 2 * x
map(double, [1, 2, 3])                  [2, 4, 6]

calc = lambda (x, y, x): x * y - z
map(calc, [(1, 2, 3), (4, 5, 6)])       [-1, 14]

avg = lambda *args: sum(args) / float(len(args))
avg(1, 2, 3)                            2.0

lambda x: pass                          SyntaxError

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Как использовать в Python лямбда-функции

В Python и других языках, таких как Java, C# и даже C++, в их синтаксис добавлены лямбда-функции, в то время как языки, такие как LISP или семейство языков ML, Haskell, OCaml и F#, используют лямбда-выражения.

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

К концу этой статьи вы узнаете:

  • Как появились лямбды в Python
  • Как лямбды сравниваются с обычными объектами функций
  • Как написать лямбда-функцию
  • Какие функции в стандартной библиотеке Python используют лямбда-выражения
  • Когда использовать или избегать лямбда-функций

Примечания: Вы увидите несколько примеров кода с использованием лямбды, которые явно игнорируют лучшие практики стиля Python. Это предназначено только для иллюстрации концепций лямбда-исчисления или для демонстрации возможностей лямбд.

Эти сомнительные примеры будут противопоставляться лучшим подходам или альтернативам по мере прохождения статьи.

Все примеры, включенные в это руководство, были протестированы в Python 3.7.

Лямбда-исчисление

Лямбда-выражения в Python и других языках программирования имеют свои корни в лямбда-исчислении, модели вычислений, изобретенной Алонзо Черчем (Alonzo Church). Далее мы расскажем, когда появилось лямбда-исчисление и почему эта фундаментальная концепция появилась в экосистеме Python.

История

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

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

Функциональные языки берут свое начало в математической логике и лямбда-исчислении, в то время как императивные языки программирования охватывают основанную на состоянии модель вычислений, изобретенную Аланом Тьюрингом. Две модели вычислений, лямбда-исчисление и машины Тьюринга, могут быть переведены друг в друга. Эта эквивалентность известна как гипотеза Чёрча-Тьюринга.

Функциональные языки напрямую наследуют философию лямбда-исчисления, применяя декларативный подход программирования, которое придает особое значение абстракции, преобразование данных, композицию и чистоту (без состояния и без побочных эффектов). Примерами функциональных языков являются Haskell, Lisp или Erlang.

Напротив, машина Тьюринга привела к императивному программированию, используемому в таких языках, как Fortran, C или Python.

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

Разделение в обоих подходах относительное, поскольку некоторые функциональные языки включают императивные функции, такие как OCaml, в то время как функциональные функции проникают в императивное семейство языков, в частности, с введением лямбда-функций в Java или Python.

Python по своей сути не является функциональным языком, но на раннем этапе он принял некоторые функциональные концепции. В январе 1994 года к языку были добавлены map(), filter(), reduce() и лямбда-оператор.

Первый пример

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

Функция тождества (identity function), функция, которая возвращает свой аргумент, выражается стандартным определением функции Python с использованием ключевого слова def следующим образом:

>>> def identity(x):
...   return x

identity() принимает аргумент x и возвращает его при вызове.

Если вы воспользуетесь лямбда-конструкцией, ваш код будет следующим:

>>> lambda x: x

В приведенном выше примере выражение состоит из:

  • Ключевое слово: lambda
  • Связанная переменная: x
  • Тело: х

Примечание. В контексте этой статьи связанная переменная является аргументом лямбда-функции.

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

Напишем немного более сложный пример, функцию, которая добавляет 1 к аргументу, следующим образом:

>>> lambda x: x + 1

Применим указанную выше функцию к аргументу, заключив функцию и ее аргумент в круглые скобки:

>>> (lambda x: x + 1)(2)
3

Сокращение — это стратегия лямбда-исчисления для вычисления значения выражения. Оно состоит из замены аргумента x на 2:

(lambda x: x + 1)(2) = lambda 2: 2 + 1
                     = 2 + 1
                     = 3

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

>>> add_one = lambda x: x + 1
>>> add_one(2)
3

Вышеупомянутая лямбда-функция эквивалентна написанию этого:

def add_one(x):
    return x + 1

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

>>> full_name = lambda first, last: f'Full name: {first.title()} {last.title()}'
>>> full_name('guido', 'van rossum')
'Full name: Guido Van Rossum'

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

Анонимные функции

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

  • Анонимные функции
  • Лямбда-функции
  • Лямбда-выражения
  • Лямбда-абстракции
  • Лямбда-форма
  • Функциональные литералы

В оставшейся части этой статьи после этого раздела вы в основном увидите термин лямбда-функция.

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

>>> lambda x, y: x + y

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

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

>>> _(1, 2)
3

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

Вы не можете написать подобный код в модуле Python. Рассматривайте _ в интерпретаторе как побочный эффект, которым мы воспользовались. В модуле Python вы бы присваивали лямбда-имя или передавали лямбда-функцию. Мы будет использовать эти два подхода позже в этой статье.

Примечание. В интерактивном интерпретаторе подчеркивание (_) привязано к последнему вычисленному выражению.

Для получения более подробной информации об использовании этого специального символа в Python, посмотрите Значение подчеркивания в Python (The Meaning of Underscores in Python).

Другой шаблон, используемый в других языках, таких как JavaScript, — это немедленное выполнение лямбда-функции Python. Это называется выражением немедленного вызова функции (IIFE —  Immediately Invoked Function Expression, произносится «iffy»). Вот пример:

>>> (lambda x, y: x + y)(2, 3)
5

Вышеприведенная лямбда-функция определяется, а затем сразу вызывается с двумя аргументами (2 и 3). Возвращает значение 5, которое является суммой аргументов.

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

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

Лямбда-функция может быть функцией более высокого порядка, принимая функцию (нормальную или лямбда-функцию) в качестве аргумента, как в следующем надуманном примере:

>>> high_ord_func = lambda x, func: x + func(x)
>>> high_ord_func(2, lambda x: x * x)
6
>>> high_ord_func(2, lambda x: x + 3)
7

Python содержит функции высшего порядка в виде встроенных функций или в стандартной библиотеке. Примеры функций высшего порядка map(), filter(), functools.reduce(), а также такие ключевые функции, как sort(), sorted(), min() и max(). Мы продемонстрируем использование лямбда-функции вместе с функциями высшего порядка в разделе «Соответствующее использование лямбда-выражений».

Лямбда и обычные функции

Эта цитата из часто задаваемых вопросов по Python Design and History FAQ, похоже, задает тон в отношении общего ожидания использования лямбда-функций в Python:

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

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

Функции

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

Модуль dis предоставляет функции для анализа байт-кода Python, сгенерированного компилятором Python:

>>> import dis
>>> add = lambda x, y: x + y
>>> type(add)
<class 'function'>
>>> dis.dis(add)
  1           0 LOAD_FAST                0 (x)
              2 LOAD_FAST                1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> add
<function <lambda> at 0x7f30c6ce9ea0>

Вы можете видеть, что dis() предоставляет читаемую версию байт-кода Python, позволяющую проверять низкоуровневые инструкции, которые интерпретатор Python будет использовать при выполнении программы.

Теперь посмотрим на обычный объект функции:

>>> import dis
>>> def add(x, y): return x + y
>>> type(add)
<class 'function'>
>>> dis.dis(add)
  1           0 LOAD_FAST                0 (x)
              2 LOAD_FAST                1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> add
<function add at 0x7f30c6ce9f28>

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

Traceback

В предыдущем разделе вы видели, что в контексте лямбда-функции Python не предоставлял имя функции, а только <lambda> . Это может быть ограничением, которое следует учитывать при возникновении исключения, и в результате трассировки отображается только:

>>> div_zero = lambda x: x / 0
>>> div_zero(2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in <lambda>
ZeroDivisionError: division by zero

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

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

>>> def div_zero(x): return x / 0
>>> div_zero(2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in div_zero
ZeroDivisionError: division by zero

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

Синтаксис

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