- Функции в Python
- Вызовы
- Еще
- Инструкция return
- Возврат простого значения
- Возврат нескольких значений
- Аргументы и параметры
- Указание произвольного количества аргументов
- Позиционные аргументы
- Произвольное количество аргументов-ключевых слов
- Документирование функции
- Методы, функции и атрибуты, связанные с объектами функции
- Рекурсивные функции
- Глобальная переменная
- Присвоение функции переменной
- Анонимная функция: лямбда
- Изменяемые аргументы по умолчанию
Функции в Python
Для определения функции нужно всего лишь написать ключевое слово def перед ее именем, а после — поставить двоеточие. Следом идет блок инструкций.
Последняя строка в блоке инструкций может начинаться с return , если нужно вернуть какое-то значение. Если инструкции return нет, тогда по умолчанию функция будет возвращать объект None . Как в этом примере:
i = 0 def increment(): global i i += 1
Функция инкрементирует глобальную переменную i и возвращает None (по умолчанию).
Вызовы
Для вызова функции, которая возвращает переменную, нужно ввести:
surface = compute_surface(1.)
Для вызова функции, которая ничего не возвращает:
Еще
Функцию можно записать в одну строку, если блок инструкций представляет собой простое выражение:
Функции могут быть вложенными:
def func1(a, b): def inner_func(x): return x*x*x return inner_func(a) + inner_func(b)
Функции — это объекты, поэтому их можно присваивать переменным.
Инструкция return
Возврат простого значения
Аргументы можно использовать для изменения ввода и таким образом получать вывод функции. Но куда удобнее использовать инструкцию return , примеры которой уже встречались ранее. Если ее не написать, функция вернет значение None .
Возврат нескольких значений
Пока что функция возвращала только одно значение или не возвращала ничего (объект None). А как насчет нескольких значений? Этого можно добиться с помощью массива. Технически, это все еще один объект. Например:
def stats(data): """данные должны быть списком""" _sum = sum(data) # обратите внимание на подчеркивание, чтобы избежать переименования встроенной функции sum mean = _sum / float(len(data)) # обратите внимание на использование функции float, чтобы избежать деления на целое число variance = sum([(x-mean)**2/len(data) for x in data]) return mean,variance # возвращаем x,y — кортеж! m, v = stats([1, 2, 1])
Аргументы и параметры
В функции можно использовать неограниченное количество параметров, но число аргументов должно точно соответствовать параметрам. Эти параметры представляют собой позиционные аргументы. Также Python предоставляет возможность определять значения по умолчанию, которые можно задавать с помощью аргументов-ключевых слов.
Параметр — это имя в списке параметров в первой строке определения функции. Он получает свое значение при вызове. Аргумент — это реальное значение или ссылка на него, переданное функции при вызове. В этой функции:
x и y — это параметры, а в этой:
При определении функции параметры со значениями по умолчанию нужно указывать до позиционных аргументов:
def compute_surface(radius, pi=3.14159): return pi * radius * radius
Если использовать необязательный параметр, тогда все, что указаны справа, должны быть параметрами по умолчанию.
Выходит, что в следующем примере допущена ошибка:
def compute_surface(radius=1, pi): return pi * radius * radius
Для вызовов это работает похожим образом. Сначала нужно указывать все позиционные аргументы, а только потом необязательные:
S = compute_surface(10, pi=3.14)
На самом деле, следующий вызов корректен (можно конкретно указывать имя позиционного аргумента), но этот способ не пользуется популярностью:
S = compute_surface(radius=10, pi=3.14)
А этот вызов некорректен:
S = compute_surface(pi=3.14, 10)
При вызове функции с аргументами по умолчанию можно указать один или несколько, и порядок не будет иметь значения:
def compute_surface2(radius=1, pi=3.14159): return pi * radius * radius S = compute_surface2(radius=1, pi=3.14) S = compute_surface2(pi=3.14, radius=10.) S = compute_surface2(radius=10.)
Можно не указывать ключевые слова, но тогда порядок имеет значение. Он должен соответствовать порядку параметров в определении:
S = compute_surface2(10., 3.14) S = compute_surface2(10.)
Если ключевые слова не используются, тогда нужно указывать все аргументы:
def f(a=1,b=2, c=3): return a + b + c
Второй аргумент можно пропустить:
Чтобы обойти эту проблему, можно использовать словарь:
params = 'a':10, 'b':20> S = f(**params)
Значение по умолчанию оценивается и сохраняется только один раз при определении функции (не при вызове). Следовательно, если значение по умолчанию — это изменяемый объект, например, список или словарь, он будет меняться каждый раз при вызове функции. Чтобы избежать такого поведения, инициализацию нужно проводить внутри функции или использовать неизменяемый объект:
def inplace(x, mutable=[]): mutable.append(x) return mutable res = inplace(1) res = inplace(2) print(inplace(3))
def inplace(x, lst=None): if lst is None: lst=[] lst.append() return lst
Еще один пример изменяемого объекта, значение которого поменялось при вызове:
def change_list(seq): seq[0] = 100 original = [0, 1, 2] change_list(original) original
Дабы не допустить изменения оригинальной последовательности, нужно передать копию изменяемого объекта:
original = [0, 1, 2] change_list(original[:]) original
Указание произвольного количества аргументов
Позиционные аргументы
Иногда количество позиционных аргументов может быть переменным. Примерами таких функций могут быть max() и min() . Синтаксис для определения таких функций следующий:
def func(pos_params, *args): block statememt
При вызове функции нужно вводить команду следующим образом:
Python обрабатывает позиционные аргументы следующим образом: подставляет обычные позиционные аргументы слева направо, а затем помещает остальные позиционные аргументы в кортеж (*args), который можно использовать в функции.
def add_mean(x, *data): return x + sum(data)/float(len(data)) add_mean(10,0,1,2,-1,0,-1,1,2)
Если лишние аргументы не указаны, значением по умолчанию будет пустой кортеж.
Произвольное количество аргументов-ключевых слов
Как и в случае с позиционными аргументами можно определять произвольное количество аргументов-ключевых слов следующим образом (в сочетании с произвольным числом необязательных аргументов из прошлого раздела):
def func(pos_params, *args, **kwargs): block statememt
При вызове функции нужно писать так:
func(pos_params, kw1=arg1, kw2=arg2, ...)
Python обрабатывает аргументы-ключевые слова следующим образом: подставляет обычные позиционные аргументы слева направо, а затем помещает другие позиционные аргументы в кортеж (*args), который можно использовать в функции (см. предыдущий раздел). В конце концов, он добавляет все лишние аргументы в словарь (**kwargs), который сможет использовать функция.
def print_mean_sequences(**kwargs): def mean(data): return sum(data)/float(len(data)) for k, v in kwargs.items(): print k, mean(v) print_mean_sequences(x=[1,2,3], y=[3,3,0])
Важно, что пользователь также может использовать словарь, но перед ним нужно ставить две звездочки (**):
print_mean_sequences(**'x':[1,2,3], 'y':[3,3,0]>)
Порядок вывода также не определен, потому что словарь не отсортирован.
Документирование функции
Если изучить ее, обнаружатся два скрытых метода (которые начинаются с двух знаков нижнего подчеркивания), среди которых есть __doc__ . Он нужен для настройки документации функции. Документация в Python называется docstring и может быть объединена с функцией следующим образом:
def sum(x, y): """Первая срока - заголовок Затем следует необязательная пустая строка и текст документации. """ return x+y
Команда docstring должна быть первой инструкцией после объявления функции. Ее потом можно будет извлекать или дополнять:
print(sum.__doc__) sum.__doc__ += "some additional text"
Методы, функции и атрибуты, связанные с объектами функции
Если поискать доступные для функции атрибуты, то в списке окажутся следующие методы (в Python все является объектом — даже функция):
sum.func_closure sum.func_defaults sum.func_doc sum.func_name sum.func_code sum.func_dict sum.func_globals
И несколько скрытых методов, функций и атрибутов. Например, можно получить имя функции или модуля, в котором она определена:
>>> sum.__name__ "sum" >>> sum.__module "__main__"
Есть и другие. Вот те, которые не обсуждались:
sum.__call__ sum.__delattr__ sum.__getattribute__ sum.__setattr__ sum.__class__ sum.__dict__ sum.__globals__ sum.__new__ sum.__sizeof__ sum.__closure__ sum.__hash__ sum.__reduce__ sum.__str__ sum.__code__ sum.__format__ sum.__init__ sum.__reduce_ex__ sum.__subclasshook__ sum.__defaults__ sum.__get__ sum.__repr__
Рекурсивные функции
Рекурсия — это не особенность Python. Это общепринятая и часто используемая техника в Computer Science, когда функция вызывает сама себя. Самый известный пример — вычисление факториала n! = n * n — 1 * n -2 * … 2 *1. Зная, что 0! = 1, факториал можно записать следующим образом:
def factorial(n): if n != 0: return n * factorial(n-1) else: return 1
Другой распространенный пример — определение последовательности Фибоначчи:
def fibbonacci(n): if n >= 2: else: return 1
Важно, чтобы в ней было была конечная инструкция, иначе она никогда не закончится. Реализация вычисления факториала выше, например, не является надежной. Если указать отрицательное значение, функция будет вызывать себя бесконечно. Нужно написать так:
def factorial(n): assert n > 0 if n != 0: return n * factorial(n-1) else: return 1
Важно!
Рекурсия позволяет писать простые и элегантные функции, но это не гарантирует эффективность и высокую скорость исполнения.
Если рекурсия содержит баги (например, длится бесконечно), функции может не хватить памяти. Задать максимальное значение рекурсий можно с помощью модуля sys .
Глобальная переменная
Вот уже знакомый пример с глобальной переменной:
i = 0 def increment(): global i i += 1
Здесь функция увеличивает на 1 значение глобальной переменной i . Это способ изменять глобальную переменную, определенную вне функции. Без него функция не будет знать, что такое переменная i . Ключевое слово global можно вводить в любом месте, но переменную разрешается использовать только после ее объявления.
За редкими исключениями глобальные переменные лучше вообще не использовать.
Присвоение функции переменной
С существующей функцией func синтаксис максимально простой:
Переменным также можно присваивать встроенные функции. Таким образом позже есть возможность вызывать функцию другим именем. Такой подход называется непрямым вызовом функции.
Менять название переменной также разрешается:
def func(x): return x a1 = func a1(10)
В этом примере a1, a2 и func имеют один и тот же id. Они ссылаются на один объект.
Практический пример — рефакторинг существующего кода. Например, есть функция sq , которая вычисляет квадрат значения:
Позже ее можно переименовать, используя более осмысленное имя. Первый вариант — просто сменить имя. Проблема в том, что если в другом месте кода используется sq , то этот участок не будет работать. Лучше просто добавить следующее выражение:
Последний пример. Предположим, встроенная функция была переназначена:
Теперь к ней нельзя получить доступ, а это может стать проблемой. Чтобы вернуть ее обратно, нужно просто удалить переменную:
Анонимная функция: лямбда
Лямбда-функция — это короткая однострочная функция, которой даже не нужно имя давать. Такие выражения содержат лишь одну инструкцию, поэтому, например, if , for и while использовать нельзя. Их также можно присваивать переменным:
В отличие от функций, здесь не используется ключевое слово return . Результат работы и так возвращается.
С помощью type() можно проверить тип:
На практике эти функции редко используются. Это всего лишь элегантный способ записи, когда она содержит одну инструкцию.
power = lambda x=1, y=2: x**y square = power square(5.)
power = lambda x,y,pow=2: x**pow + y [power(x,2, 3) for x in [0,1,2]]
Изменяемые аргументы по умолчанию
>>> def foo(x=[]): ... x.append(1) ... print x ... >>> foo() [1] >>> foo() [1, 1] >>> foo() [1, 1, 1]
Вместо этого нужно использовать значение «не указано» и заменить на изменяемый объект по умолчанию:
>>> def foo(x=None): ... if x is None: ... x = [] ... x.append(1) ... print x >>> foo() [1] >>> foo() [1]