Операции над функциями питон

Функции#

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

Объявление функции ( function definition ) состоит из заголовка и тела.

  • Заголовок начинается с ключевого слова def , за которым должно следовать название (имя) функции и список формальных параметров. Завершается заголовок символом двоеточия.
  • Далее приводится тело функции, инструкции в котором приводятся с постоянным отступом вправо относительно заголовка функции.
  • Первой строкой в теле функции допускается указывать документирующую строку.
def имя_функции(параметр1, . , параметрN): "Документирующая строка." Первая инструкция в теле функции . Последняя инструкция в теле функции Инструкция снаружи тела функции 

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

def add(x, y): """Return the sum of its arguments""" return x + y print(type(add)) print(add.__name__) 

В ячейке выше на первой строке мы объявили функцию с именем add принимающую два аргумента под именами x и y .

На следующей строке располагается документирующая строка.

def add(x, y): """Return the sum of its arguments""" 

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

print(add.__doc__) print("-" * 40) help(add) 
Return the sum of its arguments ---------------------------------------- Help on function add in module __main__: add(x, y) Return the sum of its arguments

На последней строке функция возвращает результат вычисления выражения x + y вызывающему коду.

def add(x, y): """Return the sum of its arguments""" return x + y 

Управление потоком управления и возвращение значений из функции#

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

  1. встречено ключевое слово return ;
  2. достигнут конец функции;
  3. возникло необработанное исключение, которое начало распространяться по стеку вызовов.
Читайте также:  Запрос python rest api

Последний случай разбирается позднее в разделе “ Исключения ”, разберем первые два.

Если встречается конструкция вида

def имя_функции(): . return expression 

т.е. ключевое слово return и некоторое выражение expression , то вызывающему коду возвращается результат вычисления expression . Именно такая ситуация и встречается в определенной выше функции add : в качестве expression выступает выражение x + y .

Если же после ключевого слова return ничего не стоит, т.е. встречается конструкция вида

то вызывающему коду возвращается значение None .

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

def имя_функции(): print("Hello, world!") 
def имя_функции(): print("Hello, world!") return None 
def имя_функции(): print("Hello, world!") return 

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

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

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

  1. присвоить переменной;
  2. передать в качестве аргумента функции;
  3. возвращать из функции;

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

Присваивание переменной#

Присвоение переменной в python — связывание с именем. В качестве демонстрации этой возможности свяжем встроенную функцию print с именем p и вызовем её от этого имени.

p = print p("Теперь я могу вызывать функцию print от имени p") 
Теперь я могу вызывать функцию print от имени p

Передача в качестве аргумента функции#

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

def print_function_name(f): print(f.__name__) print_function_name(add) print_function_name(print_function_name) 

В ячейке выше определена примитивная функция print_function_name , которая просто печатает содержимое атрибута __name__ функции. Далее на вход этой функции сначала передаётся определенная ранее функция add . А потом на вход этой функции передаётся она сама! Да, python настолько гибкий, что функция может обработать саму себя. Правда сложно представить себе ситуацию, где такая возможность пригодится и будет лучшей из всех возможных альтернатив.

Напишем чуть более содержательную функцию apply , которая принимает на вход функцию f и список l и подменяет каждый элемент l[i] значением f(l[i]) , т.к. применяет функцию f к элементам списка l на месте.

from math import sin, pi def apply(f, l): for i in range(len(l)): l[i] = f(l[i]) return x = [0, pi/6., pi/4., pi/3., pi/2.] apply(sin, x) print(x) 
[0.0, 0.49999999999999994, 0.7071067811865476, 0.8660254037844386, 1.0]

На самом деле есть встроенная функция map, которая делает то же самое, только не на месте.

[0.0, 0.47942553860420295, 0.6496369390800625, 0.7617599814162892, 0.8414709848078965]

Возвращение из функции. Замыкание#

Функция может возвращать функцию из себя. Распространенное применение такого приема — декораторы (см. “ Декораторы ”). Одна из основных причин такой распространенности — возможность реализовать шаблон замыкание ( closure ).

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

from datetime import datetime from time import sleep def make_remembering_function(): time_of_creation = datetime.now() def remembering_function(): print(f"I was created at time_of_creation>") return remembering_function f1 = make_remembering_function() sleep(1) f2 = make_remembering_function() for f in (f1, f2): f() 
I was created at 2022-10-04 15:15:34.360450 I was created at 2022-10-04 15:15:35.372219

Разберем, как этот пример работает. Обратим внимание на функцию make_remembering_function .

def make_remembering_function(): . def remembering_function(): . return remembering_function 

Для начала обратим внимание на то, что внутри тела этой функции объявляется другая функция remembering_function и она же возвращается в качестве результата. При каждом вызове функции make_remembering_function интерпретатор заново встречает объявление функции remembering_function , создаёт функциональный объект и связывает его с именем remembering_function в пространстве локальных имен функции make_remembering_function (каждому вызову одной и той же функции соответствует своё уникальное пространство локальных имен).

Теперь обратим внимание, что созданная функция remembering_function обращается к переменной time_of_creation , которая в этой функции не объявляется.

. time_of_creation = datetime.now() def remembering_function(): print(f"I was created at time_of_creation>") . 

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

Источник

Оцените статью