Def в python: def (функция/метод) в Python
Содержание
def (функция/метод) в Python
Последовательность инструкций, возвращающая некое значение.
В функцию могут быть переданы ноль и более аргументов, которые могут использоваться в теле функции.
Для возврата значения из функции используется инструкция return
. Допускается использование нескольких return
, в том числе для раннего выхода из функции.
Функции без инструкции return
(равно как и с нею, но без указания аргумента) всё равно возвращают результат — None
.
Определение функции
Функцию можно определить при помощи ключевого слова def
, за которым должно следовать название функции и список её формальных параметров в круглых скобках. На следующих строках, выделенное отступом слева, должно располагаться тело функции.
Первой инструкцией в теле может быть литерал строки, который будет являться документацией для данной функции (строка документации — «docstring»). Некоторые утилиты и среды разработки используют такие строки для формирования интерактивной справки. Документировать код считается хорошим тоном.
def do_work(work, reverse=False):
"""Выполняет работу.В случае удачного выполнения, возвращает True,
иначе - False.
:param list work: Список для работы.
:param bool reverse: Флаг. Следует ли сделать
работу в обратном порядке
:rtype: bool
"""
В примере выше объявляется функция do_work
, с формальными параметрами work
и reverse
. Функция задокументирована (испольузется формат описания сигнатуры reStructuredText). Кроме строки документации тело функции не содержит инструкций, тем не менее функция возвращает None
.
Определение функции описывает пользовательский «объект функции» и является исполняемой инструкцией. В ходе исполнения происходит связывание имени функции в текущем локальном пространстве имён (локальной символьной таблице) с «объектом функции» — обёрткой вокруг исполняемого кода функции. Объект функции содержит ссылку на текущее глобальное пространство имён, которое будет использовано при вызове функции. Объект функции может быть в последующем связан и с другим именем (это можно использовать для переименования функций и создания псевдонимов).
Само определение функции не вызывает исполнения кода из тела функции. Код исполняется только при вызове функции.
def print_yes():
print('yes')print_yes() # yes
print_yes_alias = print_yes
print_yes_alias() # yes
Более того, ничто не мешает использовать «объект функции» как любой другой объект (например: передавать в функцию, использовать в качестве значения в словаре и т.п.).
def print_yes():
print('yes')def print_no():
print('no')
my_functions = [print_yes, print_no]
for function in my_functions:
# Переменная function будет содержать объект
# функции. Его-то мы и вызываем в следующей строке.
function()
В ходе исполнения функции формируется новая символьная таблица с локальными переменными функции: все назначения переменных оказываются в ней. При обращении к переменной, сначала производится попытка отыскать её в локальной символьной таблице, далее в таблицах обрамляющих функций, далее в глобальной таблице, и, наконец, в таблице встроенных имён.
Ввиду вышесказанного ссылаться на глобальные переменные внутри функции можно, а присвоить им значение (без использования инструкции global
) нельзя.
MY_GLOBAL = 1def set_global_1():
MY_GLOBAL = 2
def set_global_2():
global MY_GLOBAL
MY_GLOBAL = 2
print(MY_GLOBAL) # 1
set_global_1()
print(MY_GLOBAL) # 1
set_global_2()
print(MY_GLOBAL) # 2
Аргументы, с которыми была вызвана функция, также оказываются в её локальной символьной таблице.
В Питоне используется передача аргументов «по значению» (значением при этом всегда является ссылка на сам объект, но не на его значение). Однако, ввиду того, что в случаях, когда передаются изменяемые объекты, вызвавший увидит все изменения, сделанные вызываемым (например, при добавлении элементов в список), возможно лучше было бы назвать данный вид передачи «передачей по ссылке на объект».
def mutate_list(a_list):
a_list.append(0)
return Truemy_list = [1]
print(my_list) # [1]
mutate_list(my_list) # True
print(my_list) # [1, 0]
Когда функция вызывает другую функцию, для вызова создаётся новая локальная символьная таблица.
Вложенные определения
В Питоне можно вкладывать одно в другое не только определения функций (этим приёмом, в частости, пользуются при создании декораторов), но и классов (в случае необходимости).
def outer_func():# Определение функции внутри другой
# функции.
def inner_func():
return 'some'
return inner_func()
print(outer_func()) # some
def get_my_class():
# Определение класса внутри определения
# функции.
class MyClass:
my_attr = 1
return MyClass
my_class = get_my_class()
print(my_class.my_attr) # 1
Синонимы поиска: def (функция/метод), function, define, return, функции, procedure, вуа
#12 — Функции (def, lambda, return)
В уроке мы затронем тему функций в языке Python. Мы разберемся с ключевыми понятиями, такими как: def, lambda и return, а также мы научимся создавать функции и вызывать их. На основе функции нами будут построены различные мини программы.
Функции можно назвать небольшими подпрограммами, куда можно вынести повторяющийся код и обращаться к нему, когда это будет нужно. Функции значительно облегчают построение программ, так как нам не надо копировать однотипный код множество раз, а можно просто воспользоваться одной общей функцией.
Многие путают функции и методы и не понимают отличий между ними. На самом деле отличий нет, так как что методы, что функции являются одним и тем же. Функции что записаны вне классов называют функциями, а функции что записаны внутри классов называются методами.
Точно такая же ситуация обстоит с переменным. В классах переменные называются полями, а вне классов — переменными.
В Python функции создаются при помощи ключевого слова def
. Каждая функция может иметь какие-либо параметры или же не иметь их вовсе. Функции способны что-либо возвращать в ходе выполнения кода, если это требуется.
def some_test(): # Функция без параметров
x = 23
return x # Функция возвращает что-либо
def some_test_2(a, b, c): # Функция с 3 параметрами
return a * b * c # Функция возвращает результат умножение чисел
def print_something(word, prefix): # Функция с 2 параметрами
print (prefix, "-", word)
pass # Функция ничего не возвращает
Когда функция ничего не возвращает, то необходимо прописывать ключевое слово pass
.
Функции могут возвращать другие функции, тем самым вызывая их. Чтобы обратиться к функции необходимо прописать её названи и передать параметры, если таковы имеются:
res = some_test_2 (2, 67, 12)
В примере выше результат выполнения функции будет помещен в переменную res
. Далее с переменной можно работать как с обычным значением в программе.
Анонимные функции
Если функция не должна выполнять большой объем кода, то можно воспользоваться анонимной функцией. Для этого потребуется функция lambda
.
Пример создания «lambda» функции:
multiple = lambda a, b: a * b
multiple(7, 12)
Подобная функция не имеет названия, но её можно присвоить к переменной, которую в дальнейшем необходимо вызывать как обычную функцию.
синтаксис, логика и применение ~ PythonRu
Введение
Определение
Вот пример простой функции:
def compute_surface(radius):
from math import pi
return pi * radius * radius
Для определения функции нужно всего лишь написать ключевое слово def
перед ее именем, а после — поставить двоеточие. Следом идет блок инструкций.
Последняя строка в блоке инструкций может начинаться с return
, если нужно вернуть какое-то значение. Если инструкции return
нет, тогда по умолчанию функция будет возвращать объект None
. Как в этом примере:
i = 0
def increment():
global i
i += 1
Функция инкрементирует глобальную переменную i
и возвращает None
(по умолчанию).
Вызовы
Для вызова функции, которая возвращает переменную, нужно ввести:
surface = compute_surface(1.)
Для вызова функции, которая ничего не возвращает:
increment()
Еще
Функцию можно записать в одну строку, если блок инструкций представляет собой простое выражение:
def sum(a, b): return a + b
Функции могут быть вложенными:
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)
mean = _sum / float(len(data))
variance = sum([(x-mean)**2/len(data) for x in data])
return mean,variance
m, v = stats([1, 2, 1])
Аргументы и параметры
В функции можно использовать неограниченное количество параметров, но число аргументов должно точно соответствовать параметрам. Эти параметры представляют собой позиционные аргументы. Также Python предоставляет возможность определять значения по умолчанию, которые можно задавать с помощью аргументов-ключевых слов.
Параметр — это имя в списке параметров в первой строке определения функции. Он получает свое значение при вызове. Аргумент — это реальное значение или ссылка на него, переданное функции при вызове. В этой функции:
def sum(x, y):
return x + y
x и y — это параметры, а в этой:
sum(1, 2)
1 и 2 — аргументы.
При определении функции параметры со значениями по умолчанию нужно указывать до позиционных аргументов:
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
Второй аргумент можно пропустить:
f(1,,3)
Чтобы обойти эту проблему, можно использовать словарь:
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))
[1, 2, 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
[100, 1, 2]
Дабы не допустить изменения оригинальной последовательности, нужно передать копию изменяемого объекта:
original = [0, 1, 2]
change_list(original[:])
original
[0, 1, 2]
Указание произвольного количества аргументов
Позиционные аргументы
Иногда количество позиционных аргументов может быть переменным. Примерами таких функций могут быть max()
и min()
. Синтаксис для определения таких функций следующий:
def func(pos_params, *args):
block statememt
При вызове функции нужно вводить команду следующим образом:
func(pos_params, arg1, arg2, ...)
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)
10.5
Если лишние аргументы не указаны, значением по умолчанию будет пустой кортеж.
Произвольное количество аргументов-ключевых слов
Как и в случае с позиционными аргументами можно определять произвольное количество аргументов-ключевых слов следующим образом (в сочетании с произвольным числом необязательных аргументов из прошлого раздела):
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])
y 2.0
x 2.0
Важно, что пользователь также может использовать словарь, но перед ним нужно ставить две звездочки (**):
print_mean_sequences(**{'x':[1,2,3], 'y':[3,3,0]})
y 2.0
x 2.0
Порядок вывода также не определен, потому что словарь не отсортирован.
Документирование функции
Определим функцию:
def sum(s,y): return x + y
Если изучить ее, обнаружатся два скрытых метода (которые начинаются с двух знаков нижнего подчеркивания), среди которых есть __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
Другой распространенный пример — определение последовательности Фибоначчи:
f(0) = 1
f(1) = 1
f(n) = f(n-1) + f(n-2)
Рекурсивную функцию можно записать так:
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
синтаксис максимально простой:
variable = func
Переменным также можно присваивать встроенные функции. Таким образом позже есть возможность вызывать функцию другим именем. Такой подход называется непрямым вызовом функции.
Менять название переменной также разрешается:
def func(x): return x
a1 = func
a1(10)
10
a2 = a1
a2()
10
В этом примере a1, a2 и func
имеют один и тот же id. Они ссылаются на один объект.
Практический пример — рефакторинг существующего кода. Например, есть функция sq
, которая вычисляет квадрат значения:
def sq(x): return x*x
Позже ее можно переименовать, используя более осмысленное имя. Первый вариант — просто сменить имя. Проблема в том, что если в другом месте кода используется sq
, то этот участок не будет работать. Лучше просто добавить следующее выражение:
square = sq
Последний пример. Предположим, встроенная функция была переназначена:
dir = 3
Теперь к ней нельзя получить доступ, а это может стать проблемой. Чтобы вернуть ее обратно, нужно просто удалить переменную:
del dir
dir()
Анонимная функция: лямбда
Лямбда-функция — это короткая однострочная функция, которой даже не нужно имя давать. Такие выражения содержат лишь одну инструкцию, поэтому, например, if
, for
и while
использовать нельзя. Их также можно присваивать переменным:
product = lambda x,y: x*y
В отличие от функций, здесь не используется ключевое слово return
. Результат работы и так возвращается.
С помощью type()
можно проверить тип:
>>> type(product)
function
На практике эти функции редко используются. Это всего лишь элегантный способ записи, когда она содержит одну инструкцию.
power = lambda x=1, y=2: x**y
square = power
square(5.)
25
power = lambda x,y,pow=2: x**pow + y
[power(x,2, 3) for x in [0,1,2]]
[2, 3, 10]
Изменяемые аргументы по умолчанию
>>> 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]
Функции в программировании. Курс «Python. Введение в программирование»
Функция в программировании представляет собой обособленный участок кода, который можно вызывать, обратившись к нему по имени, которым он был назван. При вызове происходит выполнение команд тела функции.
Функции можно сравнить с небольшими программками, которые сами по себе, то есть автономно, не исполняются, а встраиваются в обычную программу. Нередко их так и называют – подпрограммы. Других ключевых отличий функций от программ нет. Функции также при необходимости могут получать и возвращать данные. Только обычно они их получают не с ввода (клавиатуры, файла и др.), а из вызывающей программы. Сюда же они возвращают результат своей работы.
Существует множество встроенных в язык программирования функций. С некоторыми такими в Python мы уже сталкивались. Это print()
, input()
, int()
, float()
, str()
, type()
. Код их тела нам не виден, он где-то «спрятан внутри языка». Нам же предоставляется только интерфейс – имя функции.
С другой стороны, программист всегда может определять свои функции. Их называют пользовательскими. В данном случае под «пользователем» понимают программиста, а не того, кто пользует программу. Разберемся, зачем нам эти функции, и как их создавать.
Предположим, надо три раза подряд запрашивать на ввод пару чисел и складывать их. С этой целью можно использовать цикл:
i = 0 while i < 3: a = int(input()) b = int(input()) print(a+b) i += 1
Однако, что если перед каждым запросом чисел, надо выводить надпись, зачем они нужны, и каждый раз эта надпись разная. Мы не можем прервать цикл, а затем вернуться к тому же циклу обратно. Придется отказаться от него, и тогда получится длинный код, содержащий в разных местах одинаковые участки:
print("Сколько бананов и ананасов для обезьян?") a = int(input()) b = int(input()) print("Всего", a+b, "шт.") print("Сколько жуков и червей для ежей?") a = int(input()) b = int(input()) print("Всего", a+b, "шт.") print("Сколько рыб и моллюсков для выдр?") a = int(input()) b = int(input()) print("Всего", a+b, "шт.")
Пример исполнения программы:
Сколько бананов и ананасов для обезьян? 15 5 Всего 20 шт. Сколько жуков и червей для ежей? 50 12 Всего 62 шт. Сколько рыб и моллюсков для выдр? 16 8 Всего 24 шт.
Внедрение функций позволяет решить проблему дублирования кода в разных местах программы. Благодаря им можно исполнять один и тот же участок кода не сразу, а только тогда, когда он понадобится.
Определение функции. Оператор def
В языке программирования Python функции определяются с помощью оператора def
. Рассмотрим код:
def countFood(): a = int(input()) b = int(input()) print("Всего", a+b, "шт.")
Это пример определения функции. Как и другие сложные инструкции вроде условного оператора и циклов функция состоит из заголовка и тела. Заголовок оканчивается двоеточием и переходом на новую строку. Тело имеет отступ.
Ключевое слово def
сообщает интерпретатору, что перед ним определение функции. За def
следует имя функции. Оно может быть любым, также как и всякий идентификатор, например, переменная. В программировании весьма желательно давать всему осмысленные имена. Так в данном случае функция названа «посчитатьЕду» в переводе на русский.
После имени функции ставятся скобки. В приведенном примере они пустые. Это значит, что функция не принимает никакие данные из вызывающей ее программы. Однако она могла бы их принимать, и тогда в скобках были бы указаны так называемые параметры.
После двоеточия следует тело, содержащее инструкции, которые выполняются при вызове функции. Следует различать определение функции и ее вызов. В программном коде они не рядом и не вместе. Можно определить функцию, но ни разу ее не вызвать. Нельзя вызвать функцию, которая не была определена. Определив функцию, но ни разу не вызвав ее, вы никогда не выполните ее тела.
Вызов функции
Рассмотрим полную версию программы с функцией:
def countFood(): a = int(input()) b = int(input()) print("Всего", a+b, "шт.") print("Сколько бананов и ананасов для обезьян?") countFood() print("Сколько жуков и червей для ежей?") countFood() print("Сколько рыб и моллюсков для выдр?") countFood()
После вывода на экран каждого информационного сообщения осуществляется вызов функции, который выглядит просто как упоминание ее имени со скобками. Поскольку в функцию мы ничего не передаем скобки опять же пустые. В приведенном коде функция вызывается три раза.
Когда функция вызывается, поток выполнения программы переходит к ее определению и начинает исполнять ее тело. После того, как тело функции исполнено, поток выполнения возвращается в основной код в то место, где функция вызывалась. Далее исполняется следующее за вызовом выражение.
В языке Python определение функции должно предшествовать ее вызовам. Это связано с тем, что интерпретатор читает код строка за строкой и о том, что находится ниже по течению, ему еще неизвестно. Поэтому если вызов функции предшествует ее определению, то возникает ошибка (выбрасывается исключение NameError
):
print("Сколько бананов и ананасов для обезьян?") countFood() print("Сколько жуков и червей для ежей?") countFood() print("Сколько рыб и моллюсков для выдр?") countFood() def countFood(): a = int(input()) b = int(input()) print("Всего", a+b, "шт.")
Результат:
Сколько бананов и ананасов для обезьян? Traceback (most recent call last): File "test.py", line 2, in <module> countFood() NameError: name 'countFood' is not defined
Для многих компилируемых языков это не обязательное условие. Там можно определять и вызывать функцию в произвольных местах программы. Однако для удобочитаемости кода программисты даже в этом случае предпочитают соблюдать определенные правила.
Функции придают программе структуру
Польза функций не только в возможности многократного вызова одного и того же кода из разных мест программы. Не менее важно, что благодаря им программа обретает истинную структуру. Функции как бы разделяют ее на обособленные части, каждая из которых выполняет свою конкретную задачу.
Пусть надо написать программу, вычисляющую площади разных фигур. Пользователь указывает, площадь какой фигуры он хочет вычислить. После этого вводит исходные данные. Например, длину и ширину в случае прямоугольника. Чтобы разделить поток выполнения на несколько ветвей, следует использовать оператор if-elif-else:
figure = input("1-прямоугольник, 2-треугольник, 3-круг: ") if figure == '1': a = float(input("Ширина: ")) b = float(input("Высота: ")) print("Площадь: %. 2f" % (a*b)) elif figure == '2': a = float(input("Основание: ")) h = float(input("Высота: ")) print("Площадь: %.2f" % (0.5 * a * h)) elif figure == '3': r = float(input("Радиус: ")) print("Площадь: %.2f" % (3.14 * r**2)) else: print("Ошибка ввода")
Здесь нет никаких функций, и все прекрасно. Но напишем вариант с функциями:
def rectangle(): a = float(input("Ширина: ")) b = float(input("Высота: ")) print("Площадь: %.2f" % (a*b)) def triangle(): a = float(input("Основание: ")) h = float(input("Высота: ")) print("Площадь: %.2f" % (0.5 * a * h)) def circle(): r = float(input("Радиус: ")) print("Площадь: %.2f" % (3.14 * r**2)) figure = input("1-прямоугольник, 2-треугольник, 3-круг: ") if figure == '1': rectangle() elif figure == '2': triangle() elif figure == '3': circle() else: print("Ошибка ввода")
Он кажется сложнее, а каждая из трех функций вызывается всего один раз. Однако из общей логики программы как бы убраны и обособлены инструкции для нахождения площадей. Программа теперь состоит из отдельных «кирпичиков Лего». В основной ветке мы можем комбинировать их как угодно. Она играет роль управляющего механизма.
Если нам когда-нибудь захочется вычислять площадь треугольника по формуле Герона, а не через высоту, то не придется искать код во всей программе (представьте, что она состоит из тысяч строк кода как реальные программы). Мы пойдем к месту определения функций и изменим тело одной из них.
Если понадобиться использовать эти функции в какой-нибудь другой программе, то мы сможем импортировать их туда, сославшись на данный файл с кодом (как это делается в Python, будет рассмотрено позже).
Практическая работа
В программировании можно из одной функции вызывать другую. Для иллюстрации этой возможности напишите программу по следующему описанию.
Основная ветка программы, не считая заголовков функций, состоит из одной строки кода. Это вызов функции test()
. В ней запрашивается на ввод целое число. Если оно положительное, то вызывается функция positive()
, тело которой содержит команду вывода на экран слова «Положительное». Если число отрицательное, то вызывается функция negative()
, ее тело содержит выражение вывода на экран слова «Отрицательное».
Понятно, что вызов test()
должен следовать после определения функций. Однако имеет ли значение порядок определения самих функций? То есть должны ли определения positive()
и negative()
предшествовать test()
или могут следовать после него? Проверьте вашу гипотезу, поменяв объявления функций местами. Попробуйте объяснить результат.
Примеры решения и дополнительные уроки в android-приложении и pdf-версии курса
Интерактивный учебник языка Python
1. Функции
Напомним, что в математике факториал числа n определяется как n! = 1 ⋅ 2 ⋅ … ⋅ n.
Например, 5! = 1 ⋅ 2 ⋅ 3 ⋅ 4 ⋅ 5 = 120.
Ясно, что факториал можно легко посчитать, воспользовавшись циклом for.
Представим, что нам нужно в нашей программе вычислять факториал разных чисел несколько раз (или в разных местах кода).
Конечно, можно написать вычисление факториала один раз, а затем используя Copy-Paste вставить его везде, где это будет нужно.
# вычислим 3! res = 1 for i in range(1, 4): res *= i print(res) # вычислим 5! res = 1 for i in range(1, 6): res *= i print(res)
Однако, если мы ошибёмся один раз в начальном коде, то потом эта ошибка попадёт в код во все места, куда мы скопировали вычисление факториала. Да и вообще, код занимает больше места, чем мог бы. Чтобы избежать повторного написания одной и той же логики, в языках программирования существуют функции.
Функции — это такие участки кода, которые изолированы от остальный программы и выполняются только тогда, когда вызываются.
Вы уже встречались с функциями sqrt(), len() и print(). Они все обладают общим свойством: они могут принимать параметры (ноль, один или несколько), и они могут возвращать значение (хотя могут и не возвращать). Например, функция sqrt() принимает один параметр и возвращает значение (корень числа). Функция print() принимает переменное число параметров и ничего не возвращает.
Покажем, как написать функцию factorial(), которая принимает один параметр — число, и возвращает значение — факториал этого числа.
def factorial(n): res = 1 for i in range(1, n + 1): res *= i return res print(factorial(3)) print(factorial(5))
Дадим несколько объяснений. Во-первых, код функции должен размещаться в начале программы, вернее, до того места, где мы захотим воспользоваться функцией factorial(). Первая строчка этого примера является описанием нашей функции. factorial — идентификатор, то есть имя нашей функции. После идентификатора в круглых скобках идет список параметров, которые получает наша функция. Список состоит из перечисленных через запятую идентификаторов параметров. В нашем случае список состоит из одной величины n. В конце строки ставится двоеточие.
Далее идет тело функции, оформленное в виде блока, то есть с отступом. Внутри функции вычисляется значение факториала числа n и оно сохраняется в переменной res. Функция завершается инструкцией return res, которая завершает работу функции и возвращает значение переменной res.
Инструкция return может встречаться в произвольном месте функции, ее исполнение завершает работу функции и возвращает указанное значение в место вызова. Если функция не возвращает значения, то инструкция return используется без возвращаемого значения. В функциях, которым не нужно возвращать значения, инструкция return может отсутствовать.
Приведём ещё один пример. Напишем функцию max(), которая принимает два числа и возвращает максимальное из них (на самом деле, такая функция уже встроена в Питон).
10 20
def max(a, b): if a > b: return a else: return b print(max(3, 5)) print(max(5, 3)) print(max(int(input()), int(input())))
Теперь можно написать функцию max3(), которая принимает три числа и возвращает максимальное их них.
def max(a, b): if a > b: return a else: return b def max3(a, b, c): return max(max(a, b), c) print(max3(3, 5, 4))
Встроенная функция max() в Питоне может принимать переменное число аргументов и возвращать максимум из них. Приведём пример того, как такая функция может быть написана.
def max(*a): res = a[0] for val in a[1:]: if val > res: res = val return res print(max(3, 5, 4))
Все переданные в эту функцию параметры соберутся в один кортеж с именем a, на что указывает звёздочка в строке объявления функции.
2. Локальные и глобальные переменные
Внутри функции можно использовать переменные, объявленные вне этой функции
def f(): print(a) a = 1 f()
Здесь переменной a
присваивается значение 1, и функция f()
печатает это значение, несмотря на то, что до объявления функции f
эта переменная
не инициализируется. В момент вызова функции f()
переменной a
уже присвоено значение, поэтому функция f()
может вывести его на экран.
Такие переменные (объявленные вне функции, но доступные внутри функции)
называются глобальными.
Но если инициализировать какую-то переменную внутри функции,
использовать эту переменную вне функции не удастся. Например:
def f(): a = 1 f() print(a)
Получим ошибку NameError: name 'a' is not defined
. Такие переменные, объявленные внутри функции,
называются локальными. Эти переменные становятся недоступными после выхода из функции.
Интересным получится результат, если попробовать изменить значение глобальной переменной внутри функции:
def f(): a = 1 print(a) a = 0 f() print(a)
Будут выведены числа 1 и 0. Несмотря на то, что значение переменной a
изменилось внутри функции, вне функции оно осталось прежним! Это сделано в целях
“защиты” глобальных переменных от случайного изменения из функции.
Например, если функция будет вызвана из цикла по переменной i
, а в этой функции
будет использована переменная i
также для организации цикла, то эти переменные должны
быть различными. Если вы не поняли последнее предложение, то посмотрите на следующий код и подумайте, как бы он работал,
если бы внутри функции изменялась переменная i.
def factorial(n): res = 1 for i in range(1, n + 1): res *= i return res for i in range(1, 6): print(i, '! = ', factorial(i), sep='')
Если бы глобальная переменная i изменялась внутри функции, то мы бы получили вот что:
5! = 1 5! = 2 5! = 6 5! = 24 5! = 120
Итак, если внутри функции модифицируется значение некоторой переменной,
то переменная с таким именем становится локальной переменной, и ее модификация не приведет
к изменению глобальной переменной с таким же именем.
Более формально: интерпретатор Питон считает переменную локальной для данной функции, если в её коде
есть хотя бы одна инструкция, модифицирующая значение переменной, то эта переменная считается локальной
и не может быть использована до инициализации. Инструкция, модифицирующая значение переменной — это операторы =
, +=
, а также использование переменной в качестве параметра цикла for
.
При этом даже если инструкция,
модицифицирующая переменную никогда не будет выполнена, интерпретатор это проверить
не может, и переменная все равно считается локальной. Пример:
def f(): print(a) if False: a = 0 a = 1 f()
Возникает ошибка: UnboundLocalError: local variable 'a' referenced before assignment
.
А именно, в функции f()
идентификатор a
становится локальной переменной,
т.к. в функции есть команда, модифицирующая переменную a
, пусть даже никогда и
не выполняющийся (но интерпретатор не может это отследить). Поэтому вывод переменной a
приводит к обращению к неинициализированной локальной переменной.
Чтобы функция могла изменить значение глобальной переменной, необходимо объявить эту переменную
внутри функции, как глобальную, при помощи ключевого слова global
:
def f(): global a a = 1 print(a) a = 0 f() print(a)
В этом примере на экран будет выведено 1 1, так как переменная a
объявлена, как глобальная,
и ее изменение внутри функции приводит к тому, что и вне функции переменная
будет доступна.
Тем не менее, лучше не изменять значения глобальных переменных внутри функции. Если ваша функция должна поменять
какую-то переменную, пусть лучше она вернёт это значением, и вы сами при вызове функции явно присвоите в переменную это значение.
Если следовать этим правилам, то функции получаются независимыми от кода, и их можно легко копировать из одной программы в другую.
Например, пусть ваша программа должна посчитать факториал вводимого числа, который вы потом захотите сохранить в переменной f.
Вот как это не стоит делать:
5
def factorial(n): global f res = 1 for i in range(2, n + 1): res *= i f = res n = int(input()) factorial(n) # дальше всякие действия с переменной f
Этот код написан плохо, потому что его трудно использовать ещё один раз. Если вам завтра понадобится в другой программе использовать функцию «факториал», то вы не сможете просто скопировать эту функцию отсюда и вставить в вашу новую программу. Вам придётся поменять то, как она возвращает посчитанное значение.
Гораздо лучше переписать этот пример так:
5
# начало куска кода, который можно копировать из программы в программу def factorial(n): res = 1 for i in range(2, n + 1): res *= i return res # конец куска кода n = int(input()) f = factorial(n) # дальше всякие действия с переменной f
Если нужно, чтобы функция вернула не одно значение, а два или более, то
для этого функция может вернуть список из двух или нескольких значений:
Тогда результат вызова функции можно будет использовать во множественном присваивании:
3. Рекурсия
def short_story(): print("У попа была собака, он ее любил.") print("Она съела кусок мяса, он ее убил,") print("В землю закопал и надпись написал:") short_story()
Как мы видели выше, функция может вызывать другую функцию. Но функция также может вызывать и саму себя!
Рассмотрим это на примере функции вычисления факториала. Хорошо известно, что 0!=1, 1!=1.
А как вычислить величину n! для большого n? Если бы мы могли вычислить величину (n-1)!,
то тогда мы легко вычислим n!, поскольку n!=n⋅(n-1)!. Но как вычислить (n-1)!? Если бы
мы вычислили (n-2)!, то мы сможем вычисли и (n-1)!=(n-1)⋅(n-2)!. А как вычислить (n-2)!?
Если бы… В конце концов, мы дойдем до величины 0!, которая равна 1. Таким образом, для вычисления факториала
мы можем использовать значение факториала для меньшего числа. Это можно сделать и в программе на Питоне:
def factorial(n): if n == 0: return 1 else: return n * factorial(n - 1) print(factorial(5))
Подобный прием (вызов функцией самой себя) называется рекурсией, а сама функция называется рекурсивной.
Рекурсивные функции являются мощным механизмом в программировании. К сожалению, они не всегда эффективны. Также часто использование рекурсии приводит к ошибкам. Наиболее распространенная
из таких ошибок – бесконечная рекурсия, когда цепочка вызовов функций никогда не завершается и продолжается,
пока не кончится свободная память в компьютере. Пример бесконечной рекурсии приведен в эпиграфе к этому разделу.
Две наиболее распространенные причины для бесконечной рекурсии:
- Неправильное оформление выхода из рекурсии. Например, если мы в программе вычисления факториала
забудем поставить проверкуif n == 0
, тоfactorial(0)
вызоветfactorial(-1)
,
тот вызоветfactorial(-2)
и т. д. - Рекурсивный вызов с неправильными параметрами. Например, если функция
factorial(n)
будет
вызыватьfactorial(n)
, то также получится бесконечная цепочка.
Поэтому при разработке рекурсивной функции необходимо прежде всего оформлять условия завершения рекурсии
и думать, почему рекурсия когда-либо завершит работу.
Ссылки на задачи доступны в меню слева. Эталонные решения теперь доступны на странице самой задачи.
Основы Python — кратко. Часть 5. Определение функций, основы.
/ Хабр
Начав писать главу про ООП, понял что совсем забыл освятить такой большой и нужный раздел Пайтона как функции. Тема это большая и обширная, потому, чтобы не сильно растягивать паузу между уроками, решил разделить ее на 2 части. Сначала расскажу основы, потом уже углубленные особенности Пайтоновского функциестроения.
Функции в Пайтоне объявляются не просто, а очень просто. Вот пример самой простой:
def empty_func(): pass
Начинается объявление с ключевого слова def, что как не сложно догадаться является сокращением от define. После него идет имя функции. После имени в круглых скобках задается список параметров, в данном случае отсутствующих.
Тело функции пишется с отступом со следующей строки. учтите, что в Пайтоне функции с пустым телом запрещены, потому в качестве тела приведенной выше функции используется «пустой оператор» pass.
Теперь рассмотрим пример посерьезнее.
def safe_div(x, y): """Do a safe division :-) for fun and profit""" if y != 0: z = x / y print z return z else: print "Yippie-kay-yay, motherf___er!"
В этом примере есть несколько нововведений. первое, что бросается в глаза — это строка документации (docstring), идущая сразу после тела функции.
Обычно эта строка занимает не одну строку исходного текста (простите за каламбур) и потому задается в тройных кавычках. Она предназначена для описания функции, ее предназначения, параметров и т.п. Все хорошие ИДЕ умеют с этой строкой работать. Получить к ней доступ можно и из самой программы, используя свойство __doc__:
print safe_div.__doc__
Этим свойством (да, да, именно свойством, в Пайтоне даже функции на самом деле — классы) удобно пользоваться во время сеансов работы интерактивной консоли.
>>> from ftplib import FTP >>> print FTP.__doc__ An FTP client class. To create a connection, call the class using these argument: host, user, passwd, acct These are all strings, and have default value ''. Then use self.connect() with optional host and port argument. # дальнейшее почикано мною :-)
Вернемся к нашей исходной функции. Суть ее очень проста, она принимает 2 параметра: х и у. Если у не равен 0, она делит х на у, выводит результат на экран и возвращает свое частное в виде результата. Результат функции возвращают с помощью команды return. Благодаря механизму кортежей, описанному в прошлом уроке, функции в Пайтоне могут возвращать одновременно множество объектов.
Если же делитель все-таки равен нулю, функция выводит сообщение об ошибке. Неверно было бы предположить что в этом случае функция ничего не вернет. Правильнее будет сказать что функция вернет «ничего» 🙂 Иначе говоря, если в функции отсутствует оператор return, или же он вызван без параметров, то функция возвращает специальное значение None. В этом легко убедиться вызвав что-то типа print safe_div(10, 0).
Вот пример слегка посложнее, он взят из доклада-презентации Гвидо ван Россума.
def gcd(a, b): "Нахождение НОД" while a != 0: a,b = b%a,a # параллельное определение return b
Данная функция находит наибольший общий делитель двух чисел.
В общем, следует учитывать, что параметры в функции Пайтоном передаются по ссылке. Еще одним, возможно нетривиальным фактом к которому придется привыкать — является тот факт что сами функции являются значением, которое можно присваивать. Если воспользоваться нашей функцией safe_div для дальнейших экспериментов, то можно написать следующий код.
mystic_function = safe_div print mystic_function(10, 4)
Вот на этот раз и все, «за бортом» осталось еще много аспектов определения функций в Пайтоне, которые будут освещены в следующий раз.
Упражнения для проверки.
1. На основе существующей функции нахождения НОД, напишите функцию поиска НОК двух чисел.
2. Напишите подпрограмму табулирования функции, переданной в качестве аргумента. Так же аргументами задается начальное, конечное значение и шаг табуляции.
PS кстати, каков оптимальный объем «урока»? Что лучше — реже выходящие большие главы, или «лучше меньше да чаще».
Python. Урок 10. Функции в Python
Урок посвящен созданию функций в Python и работе с ними (передача аргументов, возврат значения и т. п.). Также рассмотрены lambda-функций, их особенности и использование.
По своей сути функции в Python практически ничем не отличаются от функций из других языков программирования. Функцией называют именованный фрагмент программного кода, к которому можно обратиться из другого места вашей программы (но есть lambda-функции, у которых нет имени, о них будет рассказано в конце урока). Как правило, функции создаются для работы с данными, которые передаются ей в качестве аргументов, также функция может формировать некоторое возвращаемое значение.
Для создания функции используется ключевое слово def, после которого указывается имя и список аргументов в круглых скобках. Тело функции выделяется также как тело условия (или цикла): четырьмя пробелами. Таким образом самая простая функция, которая ничего не делает, будет выглядеть так.
def fun(): pass
Возврат значения функцией осуществляется с помощью ключевого слова return, после которого указывается возвращаемое значение. Пример функции возвращающей единицу представлен ниже.
>>> def fun(): return 1 >>> fun() 1
Во многих случаях функции используют для обработки данных. Эти данные могут быть глобальными, либо передаваться в функцию через аргументы. Список аргументов определяется на этапе реализации и указывается в круглых скобках после имени функции. Например операцию сложения двух аргументов можно реализовать вот так.
>>> def summa(a, b): return a + b >>> summa(3, 4) 7
Рассмотрим еще два примера использования функции: вычисление числа Фибоначчи с использованием рекурсии и вычисление факториала с использованием цикла.
Вычисление числа Фибоначчи.
>>> def fibb(n): if n == 0: return 0 elif n == 1: return 1 elif n == 2: return 1 else: return fibb(n-1) + fibb(n-2) >>> print(fibb(10)) 55
Вычисление факториала.
>>> def factorial(n): prod = 1 for i in range(1, n+1): prod *= i return prod >>> print(factorial(5)) 120
Функцию можно присвоить переменной и использовать ее, если необходимо сократить имя. В качестве примера можно привести вариант использования функции вычисления факториала из пакета math.
>>> import math >>> f = math.factorial >>> print(f(5)) 120
Lambda-функция – это безымянная функция с произвольным числом аргументов и вычисляющая одно выражение. Тело такой функции не может содержать более одной инструкции (или выражения). Данную функцию можно использовать в рамках каких-либо конвейерных вычислений (например внутри filter(), map() и reduce()) либо самостоятельно, в тех местах, где требуется произвести какие вычисление, которые удобно “завернуть” в функцию.
>>> (lambda x: x**2)(5) 25
Lambda-функцию можно присвоить какой-либо переменной и в дальнейшем использовать ее в качестве имени функции.
>>> sqrt = lambda x: x**0.5 >>> sqrt(25) 5.0
Списки можно обрабатывать lambda-функциями внутри таких функций как map(), filter(), reduce(), о них мы ещё поговорим, а пока рассмотрим пример с map(). Функция map принимает два аргумента, первый – это функция, которая будет применена к каждому элементу списка, а второй – это список, который нужно обработать.
>>> l = [1, 2, 3, 4, 5, 6, 7] >>> list(map(lambda x: x**3, l)) [1, 8, 27, 64, 125, 216, 343]
P.S.
Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
<<< Python. Урок 9. Словари (dict) Python. Урок 11. Работа с исключениями>>>
Python-функций (def): определение с примерами
Что такое функция в Python?
В Python функция — это группа связанных операторов, выполняющих определенную задачу.
Функции помогают разбить нашу программу на более мелкие и модульные части. По мере того, как наша программа становится все больше и больше, функции делают ее более организованной и управляемой.
Кроме того, он позволяет избежать повторения и позволяет многократно использовать код.
Синтаксис функции
def имя_функции (параметры): "" "строка документации" "" выписка (а)
Выше показано определение функции, состоящее из следующих компонентов.
- Ключевое слово
def
, которое отмечает начало заголовка функции. - Имя функции, однозначно идентифицирующее функцию. Именование функций следует тем же правилам написания идентификаторов в Python.
- Параметры (аргументы), через которые мы передаем значения функции. Они не обязательны.
- Двоеточие (:) для обозначения конца заголовка функции.
- Необязательная строка документации (docstring), описывающая, что делает функция.
- Один или несколько допустимых операторов Python, составляющих тело функции. Заявления должны иметь одинаковый уровень отступа (обычно 4 пробела).
- Необязательный
return
оператор для возврата значения из функции.
Пример функции
def greet (имя):
"" "
Эта функция приветствует
человек прошел как
параметр
"" "
print («Привет,» + имя + «. Доброе утро!»)
Как вызвать функцию в Python?
После того, как мы определили функцию, мы можем вызвать ее из другой функции, программы или даже из командной строки Python.Чтобы вызвать функцию, мы просто вводим имя функции с соответствующими параметрами.
>>> привет ('Павел')
Привет, Пол. Доброе утро!
Примечание: Попробуйте запустить приведенный выше код в программе Python с определением функции, чтобы увидеть результат.
def greet (имя):
"" "
Эта функция приветствует
человек прошел как
параметр
"" "
print ("Привет," + имя + ". Доброе утро!")
привет ('Пол')
Строки документов
Первая строка после заголовка функции называется строкой документации и является сокращением от строки документации.Он кратко используется для объяснения того, что делает функция.
Документация, хотя и необязательная, является хорошей практикой программирования. Если вы не помните, что ели на ужин на прошлой неделе, всегда документируйте свой код.
В приведенном выше примере у нас есть строка документации непосредственно под заголовком функции. Обычно мы используем тройные кавычки, чтобы строка документа могла занимать несколько строк. Эта строка доступна нам как атрибут функции __doc__
.
Например :
Попробуйте запустить в оболочке Python следующую команду, чтобы увидеть результат.
>>> печать (привет .__ doc__)
Эта функция приветствует
человек прошел как
параметр
Чтобы узнать больше о строках документации в Python, посетите веб-сайт Python Docstrings.
Отчет о возврате
Оператор return
используется для выхода из функции и возврата в то место, откуда она была вызвана.
Синтаксис возврата
возврат [список_выражений]
Этот оператор может содержать выражение, которое вычисляется и возвращается значение.Если в операторе нет выражения или самого оператора return
нет внутри функции, тогда функция вернет объект None
.
Например:
>>> print (привет («май»))
Привет, май. Доброе утро!
Нет
Здесь Нет
— это возвращаемое значение, поскольку greet ()
напрямую печатает имя, а оператор return
не используется.
Пример возврата
def absolute_value (число):
"" "Эта функция возвращает абсолютное
значение введенного числа "" "
если число> = 0:
вернуть номер
еще:
return -num
печать (абсолютное_значение (2))
печать (абсолютное_значение (-4))
Выход
2 4
Как функция работает в Python?
Работа функций в Python
Объем и время жизни переменных
Объем переменной — это часть программы, в которой эта переменная распознается.Параметры и переменные, определенные внутри функции, не видны снаружи функции. Следовательно, они имеют локальный охват.
Время жизни переменной — это период, в течение которого переменная находится в памяти. Время жизни переменных внутри функции — до тех пор, пока функция выполняется.
Они уничтожаются, когда мы возвращаемся из функции. Следовательно, функция не запоминает значение переменной из своих предыдущих вызовов.
Вот пример, иллюстрирующий область действия переменной внутри функции.
def my_func ():
х = 10
print ("Значение внутри функции:", x)
х = 20
my_func ()
print ("Значение вне функции:", x)
Выход
Значение внутри функции: 10 Значение вне функции: 20
Здесь мы видим, что значение x изначально равно 20. Несмотря на то, что функция my_func ()
изменила значение x на 10, это не повлияло на значение вне функции.
Это связано с тем, что переменная x внутри функции отличается (локальная для функции) от переменной снаружи.Хотя у них одинаковые имена, это две разные переменные с разными областями действия.
С другой стороны, переменные вне функции видны изнутри. У них глобальный размах.
Мы можем читать эти значения изнутри функции, но не можем их изменять (записывать). Чтобы изменить значение переменных вне функции, они должны быть объявлены как глобальные переменные с использованием ключевого слова global
.
Типы функций
В принципе, мы можем разделить функции на следующие два типа:
- Встроенные функции — Функции, встроенные в Python.
- Пользовательские функции — Функции, определяемые самими пользователями.
Аргументы функции Python (по умолчанию, ключевое слово и произвольное)
Аргументы
В теме, посвященной пользовательским функциям, мы узнали об определении функции и ее вызове. В противном случае вызов функции приведет к ошибке. Вот пример.
def greet (имя, сообщение):
"" "Эта функция приветствует
человек с предоставленным сообщением "" "
print ("Привет", name + ',' + msg)
привет («Моника», «Доброе утро!»)
Выход
Привет Моника, Доброе утро!
Здесь функция greet ()
имеет два параметра.
Поскольку мы вызвали эту функцию с двумя аргументами, она работает плавно, и мы не получаем никаких ошибок.
Если мы вызовем его с другим количеством аргументов, интерпретатор выдаст сообщение об ошибке. Ниже приведен вызов этой функции с одним аргументом и без аргументов вместе с соответствующими сообщениями об ошибках.
>>> greet ("Monica") # только один аргумент TypeError: greet () отсутствует 1 обязательный позиционный аргумент: 'msg'
>>> greet () # без аргументов TypeError: greet () отсутствует 2 обязательных позиционных аргумента: 'name' и 'msg'
Аргументы функции переменной
До сих пор функции имели фиксированное количество аргументов.В Python есть и другие способы определить функцию, которая может принимать переменное количество аргументов.
Ниже описаны три различные формы этого типа.
Аргументы Python по умолчанию
Аргументы функции могут иметь значения по умолчанию в Python.
Мы можем предоставить аргументу значение по умолчанию, используя оператор присваивания (=). Вот пример.
def greet (name, msg = "Доброе утро!"):
"" "
Эта функция приветствует
человек с
предоставленное сообщение.Если сообщение не предоставлено,
по умолчанию "Хорошо"
утро!"
"" "
print ("Привет", name + ',' + msg)
привет («Катя»)
greet («Брюс», «Как поживаешь?»)
Выход
Привет Кейт, Доброе утро! Привет, Брюс, как поживаешь?
В этой функции параметр имя
не имеет значения по умолчанию и требуется (обязательно) во время вызова.
С другой стороны, параметр msg
имеет значение по умолчанию «Доброе утро!»
.Так что во время разговора это необязательно. Если значение указано, оно перезапишет значение по умолчанию.
Любое количество аргументов в функции может иметь значение по умолчанию. Но если у нас есть аргумент по умолчанию, все аргументы справа также должны иметь значения по умолчанию.
Это означает, что аргументы не по умолчанию не могут следовать за аргументами по умолчанию. Например, если бы мы определили заголовок функции выше как:
def greet (msg = "Доброе утро!", name):
Мы получили бы сообщение об ошибке:
SyntaxError: аргумент не по умолчанию следует за аргументом по умолчанию
Аргументы ключевого слова Python
Когда мы вызываем функцию с некоторыми значениями, эти значения присваиваются аргументам в соответствии с их положением.
Например, в приведенной выше функции greet ()
, когда мы вызвали ее как greet («Брюс», «Как дела?»)
, значение «Брюс»
присваивается аргументу name и аналогично «Как поживаете?» С
по сообщение .
Python позволяет вызывать функции с использованием аргументов ключевого слова. Когда мы вызываем функции таким образом, порядок (положение) аргументов может быть изменен. Все последующие вызовы вышеуказанной функции действительны и дают тот же результат.
# 2 аргумента ключевого слова
greet (name = "Брюс", msg = "Как поживаете?")
# 2 аргументы ключевого слова (не по порядку)
greet (msg = "Как поживаешь?", name = "Брюс")
1 позиционный, 1 аргумент ключевого слова
greet ("Брюс", msg = "Как поживаешь?")
Как мы видим, мы можем смешивать позиционные аргументы с ключевыми аргументами во время вызова функции. Но мы должны помнить, что аргументы ключевых слов должны следовать за позиционными аргументами.
Наличие позиционного аргумента после аргументов ключевого слова приведет к ошибкам.Например, вызов функции выглядит следующим образом:
приветствую (name = "Брюс", "Как поживаете?")
Приведет к ошибке:
SyntaxError: аргумент без ключевого слова после аргумента ключевого слова
Python произвольные аргументы
Иногда мы не знаем заранее количество аргументов, которые будут переданы функции. Python позволяет нам справляться с подобными ситуациями с помощью вызовов функций с произвольным количеством аргументов.
В определении функции мы используем звездочку (*) перед именем параметра, чтобы обозначить этот тип аргумента. Вот пример.
def greet (* имена):
"" "Эта функция приветствует всех
человек в кортеже имен. "" "
# names - это кортеж с аргументами
для имени в именах:
print ("Привет", имя)
привет («Моника», «Люк», «Стив», «Джон»)
Выход
Привет Моника Привет Люк Привет Стив Привет Джон
Здесь мы вызвали функцию с несколькими аргументами.Эти аргументы упаковываются в кортеж перед передачей в функцию. Внутри функции мы используем цикл для
, чтобы получить обратно все аргументы.
встроенных функций Python | Programiz
Питон абс ()
возвращает абсолютное значение числа
Python все ()
возвращает истину, если все элементы в итерации имеют значение истина
Python любой ()
Проверяет, является ли какой-либо элемент Iterable истинным
Python ascii ()
Возвращает строку, содержащую представление для печати
Питон бен ()
преобразует целое число в двоичную строку
Python bool ()
Преобразует значение в логическое
Python массив байтов ()
возвращает массив заданного размера байта
байтов Python ()
возвращает неизменяемый объект байтов
Python вызываемый ()
Проверяет, доступен ли объект для вызова
Python chr ()
Возвращает символ (строку) из целого числа
Python classmethod ()
возвращает метод класса для данной функции
Компиляция Python ()
Возвращает объект кода Python
Комплекс Python ()
Создает комплексное число
Python delattr ()
Удаляет атрибут из объекта
Python dict ()
Создает словарь
Python dir ()
Пытается вернуть атрибуты объекта
Python divmod ()
Возвращает кортеж частного и остатка
Python перечислить ()
Возвращает объект перечисления
Python eval ()
Запускает код Python в программе
Python exec ()
Выполняет динамически созданную программу
Фильтр Python ()
создает итератор из истинных элементов
Python с плавающей запятой ()
возвращает число с плавающей запятой из числа, строка
Формат Python ()
возвращает форматированное представление значения
Питон Frozenset ()
возвращает неизменяемый объект Frozenset
Python getattr ()
возвращает значение именованного атрибута объекта
Глобальные файлы Python ()
возвращает словарь текущей глобальной таблицы символов
Python hasattr ()
возвращает, имеет ли объект именованный атрибут
Хэш Python ()
возвращает хеш-значение объекта
Справка Python ()
Вызывает встроенную справочную систему
Шестнадцатеричный код Python ()
Преобразует в целое число в шестнадцатеричное
Идентификатор Python ()
Возвращает Идентификатор объекта
Вход Python ()
читает и возвращает строку
Python int ()
возвращает целое число из числа или строки
Python isinstance ()
Проверяет, является ли объект экземпляром класса
Python issubclass ()
Проверяет, является ли класс подклассом другого класса
Python iter ()
возвращает итератор
Python len ()
Возвращает длину объекта
Список Python ()
создает список в Python
Локальные жители Python ()
Возвращает словарь текущей локальной таблицы символов
Карта Python ()
Применяет функцию и возвращает список
Python макс. ()
возвращает самый большой элемент
Python memoryview ()
возвращает память аргумента
Python min ()
возвращает наименьшее значение
Python следующий ()
Получает следующий элемент из итератора
Объект Python ()
создает безликий объект
Python oct ()
возвращает восьмеричное представление целого числа
Python открытый ()
Возвращает объект файла
Python ord ()
возвращает целое число символа Unicode
Python pow ()
возвращает степень числа
.
Python print ()
Печать заданного объекта
Свойство Python ()
возвращает атрибут свойства
Диапазон Python ()
возвращает последовательность целых чисел от начала до конца
Python repr ()
возвращает печатное представление объекта
Python перевернутый ()
возвращает обратный итератор последовательности
Питон круглый ()
округляет число до указанных десятичных знаков
Набор Python ()
создает и возвращает набор
Python setattr ()
устанавливает значение атрибута объекта
фрагмент Python ()
возвращает объект среза
Python отсортировано ()
возвращает отсортированный список из заданного итеративного
Статический метод Python ()
преобразует метод в статический
Python str ()
возвращает строковую версию объекта
Python сумма ()
Добавляет элементы Iterable
Python супер ()
Возвращает прокси-объект базового класса
Кортеж Python ()
Возвращает кортеж
Тип Python ()
Возвращает тип объекта
Python vars ()
Возвращает атрибут __dict__
Python zip ()
Возвращает итератор кортежей
Python __import __ ()
Функция, вызываемая оператором импорта
функций Python
Функция — это блок кода, который выполняется только при вызове.
В функцию можно передавать данные, называемые параметрами.
В результате функция может возвращать данные.
Создание функции
В Python функция определяется с использованием def
ключевое слово:
Пример
def my_function ():
print («Привет от функции»)
Вызов функции
Чтобы вызвать функцию, используйте имя функции, за которым следует скобка:
Пример
def my_function ():
print («Привет от функции»)
my_function ()
Попробуй сам »
Аргументы
Информация может передаваться в функции как аргументы.
Аргументы указываются после имени функции в круглых скобках.
Вы можете добавить сколько угодно аргументов, просто разделив их запятыми.
В следующем примере есть функция с одним аргументом (fname).
Когда функция вызывается, мы передаем имя,
который используется внутри функции для вывода полного имени:
Пример
def my_function ( fname ):
print (fname + «Refsnes»)
my_function ( «Emil» )
my_function ( «Tobias» )
my_function ( «Linus» )
Попробуй сам »
Аргументы часто сокращаются до args в документации Python.
Параметры или аргументы?
Термины параметр и аргумент могут использоваться для одного и того же: информации, которая передается в функцию.
С точки зрения функции:
Параметр — это переменная, указанная в скобках в определении функции.
Аргумент — это значение, которое отправляется функции при ее вызове.
Количество аргументов
По умолчанию функция должна вызываться с правильным количеством аргументов.Это означает, что если ваша функция ожидает 2 аргумента, вы должны вызвать функцию
с 2 аргументами, не больше и не меньше.
Пример
Эта функция ожидает 2 аргумента и получает 2 аргумента:
def my_function (fname, lname):
print (fname + «» + lname)
my_function («Emil», «Refsnes»)
Попробуй сам »
Если вы попытаетесь вызвать функцию с 1 или 3 аргументами, вы получите ошибку:
Пример
Эта функция ожидает 2 аргумента, но получает только 1:
def my_function (fname, lname):
print (fname + «» + lname)
my_function («Emil»)
Попробуй сам »
Произвольные аргументы, * args
Если вы не знаете, сколько аргументов будет передано вашей функции,
добавьте *
перед именем параметра в определении функции.
Таким образом, функция получит кортеж из , аргументов и сможет обращаться к элементам соответственно:
Пример
Если количество аргументов неизвестно, добавьте *
перед именем параметра:
def my_function (* kids):
print («Самый младший ребенок
is «+ kids [2])
my_function (» Эмиль «,» Тобиас «,» Линус «)
Попробуй сам »
Произвольные аргументы часто сокращаются до * args в документации Python.
Аргументы ключевого слова
Вы также можете отправлять аргументы с синтаксисом ключ = значение .
Таким образом, порядок аргументов не имеет значения.
Пример
def my_function (child3, child2, child1):
print («Самый младший ребенок
is «+ child3)
my_function (child1 =» Emil «, child2 =» Tobias «, child3 =» Linus «)
Попробуй сам »
Фраза Аргументы ключевого слова часто сокращается до kwargs в документации Python.
Аргументы произвольного ключевого слова, ** kwargs
Если вы не знаете, сколько аргументов ключевого слова будет передано в вашу функцию,
добавьте две звездочки: **
перед именем параметра в определении функции.
Таким образом, функция получит словарь , аргументов и сможет получить доступ к элементам соответственно:
Пример
Если количество аргументов ключевого слова неизвестно, добавьте двойной
**
перед именем параметра:
def my_function (** kid):
print («Его фамилия» + kid [«lname»])
my_function (fname = «Tobias», lname = «Refsnes»)
Попробуй сам »
Произвольные аргументы Kword часто сокращаются до ** kwargs в документации Python.
Значение параметра по умолчанию
В следующем примере показано, как использовать значение параметра по умолчанию.
Если мы вызываем функцию без аргументов, она использует значение по умолчанию:
Пример
def my_function ( country = «Норвегия» ):
print («Я из» +
страна)
my_function («Швеция»)
my_function («Индия»)
my_function ()
my_function («Бразилия»)
Попробуй сам »
Передача списка в качестве аргумента
Вы можете отправлять аргументы любых типов данных функции (строка, число, список, словарь и т. Д.).),
и это будет
обрабатываться как один и тот же тип данных внутри функции.
Например. если вы отправите список в качестве аргумента, он все равно будет списком, когда он
достигает функции:
Пример
def my_function (food):
для x в food:
print (x)
fruit = [«яблоко», «банан», «вишня»]
my_function (fruit)
Попробуй сам »
Возвращаемые значения
Чтобы функция возвращала значение, используйте return
выписка:
Пример
def my_function (x):
return 5 * x
print (my_function (3))
print (my_function (5))
печать (моя_функция (9))
Попробуй сам »
Пропуск Заявление
определение функции
не может быть пустым, но если
у вас по какой-то причине есть определение функции без содержимого, введите оператор pass
, чтобы избежать ошибки.
Рекурсия
Python также принимает рекурсию функций, что означает, что определенная функция может вызывать сама себя.
Рекурсия — это общая математическая и программная концепция. Это означает, что функция вызывает сама себя. Это имеет то преимущество, что вы можете перебирать данные для достижения результата.
Разработчик должен быть очень осторожен с рекурсией, так как довольно легко ускользнуть от написания функции, которая никогда не завершается, или функции, которая использует избыточные объемы памяти или мощности процессора.Однако при правильном написании рекурсия может быть очень эффективным и математически элегантным подходом к программированию.
В этом примере tri_recursion () — это функция, которую мы определили для вызова самой себя («рекурсивная»). Мы используем переменную k в качестве данных, которая уменьшается на (-1) каждый раз, когда мы выполняем рекурсию. Рекурсия заканчивается, когда условие не больше 0 (т.е. когда оно равно 0).
Новому разработчику может потребоваться некоторое время, чтобы понять, как именно это работает, лучший способ выяснить это — протестировать и изменить его.
Пример
Пример рекурсии
def tri_recursion (k):
если (k> 0):
результат = k + tri_recursion (k — 1)
print (результат)
еще:
результат = 0
вернуть результат
print («\ n \ nРезультаты примера рекурсии»)
tri_recursion (6)
Попробуй сам »
Определение вашей собственной функции Python — Настоящий Python
На протяжении предыдущих руководств этой серии вы видели множество примеров, демонстрирующих использование встроенных функций Python.В этом руководстве вы узнаете, как определить вашу собственную функцию Python . Вы узнаете, когда разделить вашу программу на отдельные пользовательские функции и какие инструменты вам понадобятся для этого.
Из этого руководства вы узнаете:
- Как функции работают в Python и почему они полезны
- Как определить и вызвать вашу собственную функцию Python
- Механизмы передачи аргументов вашей функции
- Как для вернуть данные из вашей функции обратно в вызывающую среду
Функции в Python
Возможно, вы знакомы с математической концепцией функции .Функция — это связь или отображение между одним или несколькими входами и набором выходов. В математике функция обычно представлена так:
Здесь f
— это функция, которая работает на входах x
и y
. Результатом функции будет z
. Однако функции программирования гораздо более обобщены и универсальны, чем это математическое определение. Фактически, правильное определение и использование функций настолько критично для правильной разработки программного обеспечения, что практически все современные языки программирования поддерживают как встроенные, так и определяемые пользователем функции.
В программировании функция — это автономный блок кода, который инкапсулирует конкретную задачу или связанную группу задач. В предыдущих руководствах этой серии вы познакомились с некоторыми встроенными функциями, предоставляемыми Python. id ()
, например, принимает один аргумент и возвращает уникальный целочисленный идентификатор этого объекта:
>>>
>>> s = 'foobar'
>>> id (s)
56313440
len ()
возвращает длину переданного ему аргумента:
>>>
>>> a = ['foo', 'bar', 'baz', 'qux']
>>> len (а)
4
any ()
принимает в качестве аргумента итерацию и возвращает True
, если какой-либо из элементов в итерации является истинным, и False
в противном случае:
>>>
>>> любое ([Ложь, Ложь, Ложь])
Ложь
>>> любое ([False, True, False])
Правда
>>> any (['bar' == 'baz', len ('foo') == 4, 'qux' в {'foo', 'bar', 'baz'}])
Ложь
>>> any (['bar' == 'baz', len ('foo') == 3, 'qux' in {'foo', 'bar', 'baz'}])
Правда
Каждая из этих встроенных функций выполняет определенную задачу.Код, выполняющий задачу, где-то определен, но вам не нужно знать, где и даже как он работает. Все, о чем вам нужно знать, это интерфейс функции:
- Какие аргументы (если есть) нужно
- Какие значения (если есть) возвращает
Затем вы вызываете функцию и передаете ей соответствующие аргументы. Выполнение программы переходит к обозначенному фрагменту кода и выполняет свои полезные функции. Когда функция завершена, выполнение возвращается к вашему коду с того места, где оно было остановлено.Функция может возвращать или не возвращать данные для использования вашим кодом, как в приведенных выше примерах.
Когда вы определяете свою собственную функцию Python, она работает точно так же. Где-то в коде вы вызываете функцию Python, и выполнение программы передается в тело кода, составляющего функцию.
Примечание: В этом случае вы будете знать, где находится код и как именно он работает, потому что вы его написали!
Когда функция завершена, выполнение возвращается в то место, где функция была вызвана.В зависимости от того, как вы спроектировали интерфейс функции, данные могут передаваться при вызове функции, а возвращаемые значения могут передаваться обратно после ее завершения.
Важность функций Python
Практически все языки программирования, используемые сегодня, поддерживают определенные пользователем функции, хотя их не всегда называют функциями. На других языках вы можете встретить их как одно из следующих:
- Подпрограммы
- Процедуры
- Методы
- Подпрограммы
Итак, зачем вообще определять функции? Есть несколько очень веских причин.Давайте пройдемся по нескольким.
Абстракция и возможность повторного использования
Предположим, вы пишете код, который делает что-то полезное. По мере продолжения разработки вы обнаружите, что задача, выполняемая этим кодом, вам часто требуется во многих различных местах вашего приложения. Что вы должны сделать? Что ж, вы можете просто копировать код снова и снова, используя возможность копирования и вставки вашего редактора.
Позже вы, вероятно, решите, что рассматриваемый код необходимо изменить.Вы либо обнаружите, что с ним что-то не так, что нужно исправить, либо захотите как-то улучшить его. Если копии кода разбросаны по всему приложению, вам нужно будет внести необходимые изменения в каждом месте.
Примечание: На первый взгляд это может показаться разумным решением, но в долгосрочной перспективе это может стать кошмаром для обслуживания! Хотя ваш редактор кода может помочь, предоставляя функцию поиска и замены, этот метод подвержен ошибкам, и вы можете легко внести в свой код ошибки, которые будет трудно найти.
Лучшее решение — это определить функцию Python, которая выполняет задачу . В любом месте вашего приложения, где вам нужно выполнить задачу, вы просто вызываете функцию. В дальнейшем, если вы решите изменить способ его работы, вам нужно будет изменить код только в одном месте, то есть в том месте, где определена функция. Изменения будут автоматически приняты везде, где вызывается функция.
Абстракция функциональности в определение функции является примером принципа «не повторяйся» (DRY) при разработке программного обеспечения.Это, пожалуй, самая сильная мотивация для использования функций.
Модульность
Функции
позволяют разбить сложные процессы на более мелкие этапы. Представьте, например, что у вас есть программа, которая читает файл, обрабатывает его содержимое, а затем записывает выходной файл. Ваш код может выглядеть так:
# Основная программа
# Код для чтения файла в
<заявление>
<заявление>
<заявление>
<заявление>
# Код для обработки файла
<заявление>
<заявление>
<заявление>
<заявление>
# Код для записи файла
<заявление>
<заявление>
<заявление>
<заявление>
В этом примере основная программа — это связка кода, связанного в длинную последовательность, с пробелами и комментариями, которые помогают упорядочить ее.Однако если бы код стал намного длиннее и сложнее, вам было бы все труднее осмысливать его.
В качестве альтернативы вы можете структурировать код примерно так:
def read_file ():
# Код для чтения файла в
<заявление>
<заявление>
<заявление>
<заявление>
def process_file ():
# Код для обработки файла
<заявление>
<заявление>
<заявление>
<заявление>
def write_file ():
# Код для записи файла
<заявление>
<заявление>
<заявление>
<заявление>
# Основная программа
read_file ()
process_file ()
write_file ()
Этот пример — модульный .Вместо того, чтобы связывать весь код вместе, он разбит на отдельные функции, каждая из которых ориентирована на конкретную задачу. Эти задачи: чтение , процесс и запись . Теперь основной программе просто нужно вызвать каждый из них по очереди.
Примечание: Ключевое слово def
вводит новое определение функции Python. Вы все об этом узнаете очень скоро.
В жизни вы делаете такие вещи все время, даже если не думаете об этом явно.Если бы вы захотели переместить несколько полок, заполненных вещами, из одной стороны гаража в другую, то, надеюсь, вы не станете просто стоять и бесцельно думать: «Ой, блин. Мне нужно перевезти все это туда! Как я это сделал???» Вы бы разделили задание на управляемые шаги:
- Уберите все с полок.
- Разобрать полки.
- Перенести части полки через гараж на новое место.
- Снова соберите полки.
- Отнесите вещи через гараж.
- Положите вещи обратно на полки.
Разделение большой задачи на более мелкие и небольшие подзадачи помогает упростить рассмотрение большой задачи и управление ею. По мере того, как программы становятся более сложными, становится все более выгодным модулировать их таким образом.
Разделение пространства имен
Пространство имен — это область программы, в которой идентификаторы имеют значение.Как вы увидите ниже, при вызове функции Python для этой функции создается новое пространство имен, которое отличается от всех других уже существующих пространств имен.
Практический результат этого состоит в том, что переменные можно определять и использовать в функции Python, даже если они имеют то же имя, что и переменные, определенные в других функциях или в основной программе. В этих случаях не будет путаницы или вмешательства, потому что они хранятся в отдельных пространствах имен.
Это означает, что, когда вы пишете код внутри функции, вы можете использовать имена и идентификаторы переменных, не беспокоясь о том, используются ли они уже где-то вне функции.Это помогает значительно минимизировать ошибки в коде.
Надеюсь, вы достаточно убедились в достоинствах функций и хотите их создать! Посмотрим как.
Вызов функций и определение
Обычный синтаксис для определения функции Python следующий:
def <имя_функции> ([<параметры>]):
<заявление (я)>
Компоненты определения поясняются в таблице ниже:
Компонент | Значение |
---|---|
по умолчанию | Ключевое слово, информирующее Python о том, что функция определяется |
<имя_функции> | Действительный идентификатор Python, который называет функцию |
<параметры> | Необязательный список параметров, разделенных запятыми, которые могут быть переданы функции |
: | Пунктуация, обозначающая конец заголовка функции Python (имя и список параметров) |
<выписки> | Блок действительных операторов Python |
Последний элемент,
, называется телом функции.Тело — это блок операторов, который будет выполняться при вызове функции. Тело функции Python определяется отступом в соответствии с правилом off-side. Это то же самое, что и блоки кода, связанные со структурой управления, например, if
или while
.
Синтаксис для вызова функции Python следующий:
<имя_функции> ([<аргументы>])
<аргументы>
— значения, переданные в функцию.Они соответствуют <параметры>
в определении функции Python. Вы можете определить функцию, которая не принимает никаких аргументов, но круглые скобки по-прежнему необходимы. И определение функции, и вызов функции всегда должны включать круглые скобки, даже если они пусты.
Как обычно, вы начнете с небольшого примера, а затем добавите сложности. Помня об освященной веками математической традиции, вы вызовете свою первую функцию Python f ()
. Вот файл сценария foo.py
, который определяет и вызывает f ()
:
1def f ():
2 s = '- Внутри f ()'
3 отпечатка (ов)
4
5print ('Перед вызовом f ()')
6f ()
7print ('После вызова f ()')
Вот как работает этот код:
Строка 1 использует ключевое слово
def
, чтобы указать, что функция определяется. Выполнение оператораdef
просто создает определениеf ()
. Все следующие строки с отступом (строки 2–3) становятся частью телаf ()
и сохраняются как его определение, но еще не выполняются.Строка 4 — это небольшой пробел между определением функции и первой строкой основной программы. Хотя это и не является синтаксически необходимым, это приятно иметь. Чтобы узнать больше о пробелах вокруг определений функций Python верхнего уровня, прочтите статью Написание красивого кода Python с помощью PEP 8.
Строка 5 — это первый оператор без отступа, потому что он не является частью определения
f ()
. Это начало основной программы.Когда выполняется основная программа, этот оператор выполняется первым.Линия 6 — это звонок на номер
f ()
. Обратите внимание, что пустые круглые скобки всегда требуются как в определении функции, так и при ее вызове, даже если нет параметров или аргументов. Выполнение переходит кf ()
, и выполняются операторы в телеf ()
.Строка 7 — это следующая строка, которая выполняется после завершения тела
f ()
.Выполнение возвращается к этому операторуprint ()
.
Последовательность выполнения (или потока управления ) для foo.py
показана на следующей диаграмме:
Когда foo.py
запускается из командной строки Windows, результат будет следующим:
C: \ Users \ john \ Documents \ Python \ doc> python foo.py
Перед вызовом f ()
- Внутри f ()
После вызова f ()
Иногда вам может понадобиться определить пустую функцию, которая ничего не делает.Это называется заглушкой , которая обычно является временным заполнителем для функции Python, которая будет полностью реализована позже. Как блок в управляющей структуре не может быть пустым, так и тело функции не может быть пустым. Чтобы определить функцию-заглушку, используйте оператор pass
:
>>>
>>> def f ():
... проходить
...
>>> f ()
Как вы можете видеть выше, вызов функции-заглушки синтаксически допустим, но ничего не делает.
Передача аргумента
До сих пор в этом руководстве функции, которые вы определили, не принимали никаких аргументов. Иногда это может быть полезно, и вы иногда будете писать такие функции. Чаще, однако, вам понадобится передавать данные в функцию , чтобы ее поведение могло изменяться от одного вызова к другому. Посмотрим, как это сделать.
Позиционные аргументы
Самый простой способ передать аргументы функции Python — использовать позиционные аргументы (также называемые обязательными аргументами ).В определении функции вы указываете в скобках список параметров, разделенных запятыми:
>>>
>>> def f (кол-во, шт., Цена):
... print (f '{qty} {item} cost $ {price: .2f}')
...
При вызове функции вы указываете соответствующий список аргументов:
>>>
>>> f (6, 'бананы', 1.74)
6 бананов стоят 1,74 доллара
Параметры ( кол-во
, предмет
и цена
) ведут себя как переменные , которые определены локально для функции.Когда функция вызывается, переданные аргументы ( 6
, «бананы»,
и 1.74
) привязывают к параметрам по порядку, как если бы путем присвоения переменной:
Параметр | Аргумент | |
---|---|---|
шт. | ← | 6 |
товар | ← | бананы |
цена | ← | 1.74 |
В некоторых текстах по программированию параметры, указанные в определении функции, называются формальными параметрами , а аргументы в вызове функции называются фактическими параметрами :
Хотя позиционные аргументы являются наиболее простым способом передачи данных в функцию, они также обеспечивают наименьшую гибкость. Во-первых, порядок аргументов в вызове должен соответствовать порядку параметров в определении.Конечно, ничто не мешает вам указывать позиционные аргументы не по порядку:
>>>
>>> f ('бананы', 1.74, 6)
бананы 1.74 стоят $ 6.00
Функция может даже работать, как в приведенном выше примере, но маловероятно, что она даст правильные результаты. Это ответственность программиста, который определяет функцию, чтобы задокументировать, какими должны быть соответствующие аргументы , и ответственность пользователя функции — знать эту информацию и соблюдать ее.
С позиционными аргументами аргументы в вызове и параметры в определении должны согласовываться не только по порядку, но и по номеру и . По этой причине позиционные аргументы также называются обязательными аргументами. Вы не можете ничего пропустить при вызове функции:
>>>
>>> # Слишком мало аргументов
>>> f (6, 'бананы')
Отслеживание (последний вызов последний):
Файл "", строка 1, в
f (6, 'бананы')
TypeError: f () отсутствует 1 обязательный позиционный аргумент: 'цена'
Вы также не можете указать лишние:
>>>
>>> # Слишком много аргументов
>>> f (6, 'бананы', 1.74, кумкваты)
Отслеживание (последний вызов последний):
Файл "", строка 1, в
f (6, «бананы», 1,74, «кумкват»)
TypeError: f () принимает 3 позиционных аргумента, но было дано 4
Позиционные аргументы концептуально просты в использовании, но они не очень снисходительны. Вы должны указать такое же количество аргументов в вызове функции, как и параметры в определении, и в точно таком же порядке. В следующих разделах вы увидите некоторые приемы передачи аргументов, которые ослабляют эти ограничения.
Аргументы ключевого слова
При вызове функции можно указать аргументы в форме <ключевое слово> = <значение>
. В этом случае каждое <ключевое слово>
должно соответствовать параметру в определении функции Python. Например, ранее определенная функция f ()
может быть вызвана с аргументами ключевого слова следующим образом:
>>>
>>> f (qty = 6, item = 'bananas', price = 1,74)
6 бананов стоят 1,74 доллара
Ссылка на ключевое слово, которое не соответствует ни одному из заявленных параметров, генерирует исключение:
>>>
>>> f (qty = 6, item = 'bananas', cost = 1.74)
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: f () получил неожиданный аргумент ключевого слова 'стоимость'
Использование аргументов ключевого слова снимает ограничение на порядок аргументов. Каждый аргумент ключевого слова явно обозначает конкретный параметр по имени, поэтому вы можете указать их в любом порядке, и Python все равно будет знать, какой аргумент соответствует какому параметру:
>>>
>>> f (item = 'bananas', price = 1.74, qty = 6)
6 бананов стоят 1 доллар.74
Однако, как и в случае с позиционными аргументами, количество аргументов и параметров должно совпадать:
>>>
>>> # Еще слишком мало аргументов
>>> f (кол-во = 6, элемент = 'бананы')
Отслеживание (последний вызов последний):
Файл "", строка 1, в
f (кол-во = 6, элемент = 'бананы')
TypeError: f () отсутствует 1 обязательный позиционный аргумент: 'цена'
Итак, аргументы ключевого слова допускают гибкость в порядке указания аргументов функции, но количество аргументов остается жестким.
Вы можете вызвать функцию, используя как позиционные, так и ключевые аргументы:
>>>
>>> f (6, цена = 1.74, item = 'bananas')
6 бананов стоят 1,74 доллара
>>> f (6, 'бананы', цена = 1,74)
6 бананов стоят 1,74 доллара
Когда присутствуют как позиционные аргументы, так и аргументы ключевого слова, все позиционные аргументы должны идти первыми:
>>>
>>> f (6, item = 'bananas', 1.74)
SyntaxError: позиционный аргумент следует за аргументом ключевого слова
После того, как вы указали аргумент ключевого слова, справа от него не может быть никаких позиционных аргументов.
Параметры по умолчанию
Если параметр, указанный в определении функции Python, имеет форму <имя> = <значение>
, тогда <значение>
становится значением по умолчанию для этого параметра. Параметры, определенные таким образом, называются параметрами по умолчанию или дополнительными параметрами . Пример определения функции с параметрами по умолчанию показан ниже:
>>>
>>> def f (qty = 6, item = 'bananas', price = 1.74):
... print (f '{qty} {item} cost $ {price :.2f} ')
...
Когда вызывается эта версия f ()
, любой аргумент, который не указан, принимает значение по умолчанию:
>>>
>>> f (4, 'яблоки', 2.24)
4 яблока стоят 2,24 доллара.
>>> f (4, 'яблоки')
4 яблока стоят 1,74 доллара
>>> f (4)
4 банана стоят 1,74 доллара
>>> f ()
6 бананов стоят 1,74 доллара
>>> f (item = 'кумкват', кол-во = 9)
9 кумкватов стоят 1,74 доллара
>>> f (цена = 2,29)
6 бананов стоят 2,29 доллара
Итого:
- Позиционные аргументы должны соответствовать по порядку и номеру параметрам, объявленным в определении функции.
- Аргументы ключевого слова должны совпадать с объявленными параметрами по количеству, но они могут быть указаны в произвольном порядке.
- Параметры по умолчанию позволяют опускать некоторые аргументы при вызове функции.
Изменяемые значения параметров по умолчанию
Все может стать странным, если вы укажете значение параметра по умолчанию, которое является изменяемым объектом . Рассмотрим это определение функции Python:
>>>
>>> def f (my_list = []):
... my_list.append ('###')
... вернуть my_list
...
f ()
принимает единственный параметр списка, добавляет строку '###'
в конец списка и возвращает результат:
>>>
>>> f (['foo', 'bar', 'baz'])
['foo', 'bar', 'baz', '###']
>>> f ([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5, '###']
Значение по умолчанию для параметра my_list
— пустой список, поэтому, если f ()
вызывается без каких-либо аргументов, возвращаемое значение — это список с одним элементом '###'
:
Пока все имеет смысл.Что вы ожидаете, если вызовите f ()
без каких-либо параметров второй и третий раз? Посмотрим:
>>>
>>> f ()
['###', '###']
>>> f ()
['###', '###', '###']
Ой! Вы могли ожидать, что каждый последующий вызов также будет возвращать одноэлементный список ['###']
, как и первый. Вместо этого возвращаемое значение продолжает расти. Что случилось?
В Python значения параметров по умолчанию определены только один раз , когда функция определена (то есть, когда выполняется инструкция def
).Значение по умолчанию не переопределяется каждый раз при вызове функции. Таким образом, каждый раз, когда вы вызываете f ()
без параметра, вы выполняете .append ()
в том же списке.
Вы можете продемонстрировать это с помощью id ()
:
>>>
>>> def f (my_list = []):
... печать (id (my_list))
... my_list.append ('###')
... вернуть my_list
...
>>> f ()
140095566958408
['###']
>>> f ()
140095566958408
['###', '###']
>>> f ()
140095566958408
['###', '###', '###']
Отображаемый идентификатор объекта подтверждает, что, когда для my_list
разрешено значение по умолчанию, значение будет одним и тем же объектом при каждом вызове.Поскольку списки изменяемы, каждый последующий вызов .append ()
заставляет список удлиняться. Это распространенная и довольно хорошо задокументированная ошибка, когда вы используете изменяемый объект в качестве значения параметра по умолчанию. Это потенциально приводит к путанице в поведении кода, и, вероятно, лучше этого избегать.
В качестве обходного пути рассмотрите возможность использования значения аргумента по умолчанию, которое сигнализирует , что аргумент не указан . Практически любое значение будет работать, но Нет
— обычный выбор. Когда значение дозорного указывает, что аргумент не задан, создайте новый пустой список внутри функции:
>>>
>>> def f (my_list = None):
... если my_list - None:
... my_list = []
... my_list.append ('###')
... вернуть my_list
...
>>> f ()
['###']
>>> f ()
['###']
>>> f ()
['###']
>>> f (['фу', 'бар', 'баз'])
['foo', 'bar', 'baz', '###']
>>> f ([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5, '###']
Обратите внимание, как это гарантирует, что my_list
теперь действительно по умолчанию использует пустой список всякий раз, когда f ()
вызывается без аргумента.
Передача по значению и передача по ссылке в Pascal
В разработке языков программирования есть две общие парадигмы для передачи аргумента функции:
- Передача по значению: Копия аргумента передается функции.
- Передача по ссылке: Ссылка на аргумент передается функции.
Существуют и другие механизмы, но они по сути являются вариациями этих двух. В этом разделе вы сделаете небольшой отход от Python и кратко рассмотрите Pascal, язык программирования, который проводит особенно четкое различие между этими двумя.
Примечание: Не волнуйтесь, если вы не знакомы с Паскалем! Концепции аналогичны концепциям Python, а показанные примеры сопровождаются достаточно подробным объяснением, чтобы вы могли составить общее представление.Как только вы увидели, как передача аргументов работает в Паскале, мы вернемся к Python, и вы увидите, как он сравнивается.
Вот что вам нужно знать о синтаксисе Паскаля:
- Процедуры: Процедура в Паскале похожа на функцию Python.
- Двоеточие равно: Этот оператор (
: =
) используется для присваивания в Паскале. Это аналог знака равенства (=
) в Python. -
Writeln ()
: Эта функция отображает данные в консоли, аналогично функции Pythonprint ()
.
Имея такую основу, вот первый пример Pascal:
1 // Пример Pascal # 1
2
3процедура f (fx: целое число);
4начать
5 Writeln ('Начать f (): fx =', fx);
6 FX: = 10;
7 Writeln ('Конец f (): fx =', fx);
8end;
9
10 // Основная программа
11вар
12 x: целое число;
13
14начало
15 х: = 5;
16 Writeln ('Перед f (): x =', x);
17 f (x);
18 Writeln ('После f (): x =', x);
19 конец.
Вот что происходит:
- Строка 12: Основная программа определяет целочисленную переменную
x
. - Строка 15: Первоначально
x
присваивается значение5
. - Строка 17: Затем вызывается процедура
f ()
, передаваяx
в качестве аргумента. - Строка 5: Внутри
f ()
инструкцияwriteln ()
показывает, что соответствующий параметрfx
изначально равен5
, переданному значению. - Строка 6:
fx
затем присваивается значение10
. - Строка 7: Это значение проверяется этим оператором
writeln ()
, выполняемым непосредственно перед выходом изf ()
. - Строка 18: Вернувшись в вызывающую среду основной программы, этот оператор
writeln ()
показывает, что после возвратаf ()
x
все еще остается5
, как это было до вызова процедуры. .
При выполнении этого кода генерируется следующий вывод:
Перед f (): x = 5
Начать f (): fx = 5
Конец f (): fx = 10
После f (): x = 5
В этом примере x
— это , переданное по значению , поэтому f ()
получает только копию.Когда соответствующий параметр fx
изменяется, x
не изменяется.
Примечание: Если вы хотите увидеть это в действии, вы можете запустить код самостоятельно, используя онлайн-компилятор Pascal.
Просто выполните следующие действия:
- Скопируйте код из поля кода выше.
- Посетите онлайн-компилятор Паскаля.
- В поле кода слева замените любое существующее содержимое кодом, который вы скопировали на шаге 1.
- Щелкните Выполнить .
Вы должны увидеть тот же результат, что и выше.
Теперь сравните это со следующим примером:
1 // Пример # 2 на Паскале
2
3процедура f (var fx: integer);
4начать
5 Writeln ('Начать f (): fx =', fx);
6 FX: = 10;
7 Writeln ('Конец f (): fx =', fx);
8end;
9
10 // Основная программа
11вар
12 x: целое число;
13
14начало
15 х: = 5;
16 Writeln ('Перед f (): x =', x);
17 f (x);
18 Writeln ('После f (): x =', x);
19 конец.
Этот код идентичен первому примеру с одним изменением.Это наличие слова var
перед fx
в определении процедуры f ()
в строке 3. Это означает, что аргумент f ()
— это , переданный по ссылке . Изменения, внесенные в соответствующий параметр fx
, также изменят аргумент в вызывающей среде.
Вывод этого кода такой же, как и раньше, за исключением последней строки:
Перед f (): x = 5
Начать f (): fx = 5
Конец f (): fx = 10
После f (): x = 10
Опять же, fx
присваивается значение 10
внутри f ()
, как и раньше.Но на этот раз, когда возвращается f ()
, x
в основной программе также были изменены.
Во многих языках программирования это, по сути, различие между передачей по значению и передачей по ссылке:
- Если переменная передается по значению, , тогда у функции есть копия для работы, но она не может изменить исходное значение в вызывающей среде.
- Если переменная передается по ссылке, , то любые изменения, которые функция вносит в соответствующий параметр, повлияют на значение в вызывающей среде.
Причина почему происходит от того, что означает ссылка на этих языках. Значения переменных хранятся в памяти. В Паскале и подобных языках ссылка — это, по сути, адрес этой ячейки памяти, как показано ниже:
На схеме слева x
— это память, выделенная в пространстве имен основной программы. Когда вызывается f ()
, x
— это , переданный значением , поэтому память для соответствующего параметра fx
выделяется в пространстве имен f ()
, а значение x
копируется туда. .Когда f ()
изменяет fx
, изменяется именно эта локальная копия. Значение x
в среде вызова остается неизменным.
На диаграмме справа x
— это , переданный по ссылке . Соответствующий параметр fx
указывает на фактический адрес в пространстве имен основной программы, где хранится значение x
. Когда f ()
изменяет fx
, он изменяет значение в этом месте, точно так же, как если бы основная программа изменяла саму x
.
Передача по значению и передача по ссылке в Python
Являются ли параметры в Python передачей по значению или по ссылке? Ответ таков: ни то, ни другое. Это потому, что ссылка в Python означает не то же самое, что в Паскале.
Напомним, что в Python каждая часть данных представляет собой объект . Ссылка указывает на объект, а не на конкретную ячейку памяти. Это означает, что присваивание не интерпретируется в Python так же, как в Паскале. Рассмотрим следующую пару операторов в Паскале:
Они интерпретируются следующим образом:
- Переменная
x
ссылается на конкретную ячейку памяти. - Первый оператор помещает в это место значение
5
. - Следующий оператор перезаписывает
5
и помещает вместо него10
.
Напротив, в Python аналогичные операторы присваивания выглядят следующим образом:
Эти операторы присваивания имеют следующее значение:
- Первый оператор заставляет
x
указывать на объект, значение которого составляет5
. - Следующий оператор переназначает
x
как новую ссылку на другой объект, значение которого составляет10
. Другими словами, второе присвоение повторно привязываетx
к другому объекту со значением10
.
В Python, когда вы передаете аргумент функции, происходит аналогичное повторное связывание . Рассмотрим этот пример:
>>>
1 >>> def f (fx):
2 ... fx = 10
3 ...
4 >>> х = 5
5 >>> f (x)
6 >>> х
75
В основной программе оператор x = 5
в строке 5 создает ссылку с именем x
, привязанную к объекту, значение которого составляет 5
.Затем в строке 7 вызывается f ()
с x
в качестве аргумента. При первом запуске f ()
создается новая ссылка с именем fx
, которая изначально указывает на тот же объект 5
, что и x
:
Однако, когда выполняется инструкция fx = 10
в строке 2, f ()
выполняет повторную привязку fx
к новому объекту, значение которого составляет 10
. Две ссылки, x
и fx
, не связаны друг с другом на .Ничто другое из того, что делает f ()
, не повлияет на x
, и когда f ()
завершится, x
все равно будет указывать на объект 5
, как это было до вызова функции:
Все это можно подтвердить с помощью id ()
. Вот слегка расширенная версия приведенного выше примера, которая отображает числовые идентификаторы задействованных объектов:
>>>
1 >>> def f (fx): 2 ... печать ('fx =', fx, '/ id (fx) =', id (fx)) 3... fx = 10 4 ... печать ('fx =', fx, '/ id (fx) =', id (fx)) 5 ... 6 7 >>> х = 5 8 >>> print ('x =', x, '/ id (x) =', id (x)) 9x = 5 / id (x) = 1357
8 14 15 >>> печать ('x =', x, '/ id (x) =', id (x)) 16x = 5 / id (x) = 13578 10 11 >>> f (x) 12fx = 5 / id (fx) = 1357
8 13fx = 10 / id (fx) = 1357
8
При первом запуске f ()
fx
и x
указывают на один и тот же объект, чей id ()
равен 1357
8 .После того, как f ()
выполнит оператор fx = 10
в строке 3, fx
указывает на другой объект, чей id ()
равен 1357
8 . Связь с исходным объектом в вызывающей среде теряется.
Передача аргументов в Python — это своего рода гибрид между передачей по значению и передачей по ссылке. В функцию передается ссылка на объект, но ссылка передается по значению.
Примечание. Механизм передачи аргументов Python был назван передачей путем присвоения .Это связано с тем, что имена параметров привязаны к объектам при вводе функции в Python, а присвоение также является процессом привязки имени к объекту. Вы также можете увидеть термины «передача по объекту», «передача по ссылке на объект» или «передача по совместному использованию».
Ключевой вывод здесь заключается в том, что функция Python не может изменить значение аргумента, переназначив соответствующий параметр чему-то другому. Следующий пример демонстрирует это:
>>>
>>> def f (x):
... x = 'foo'
...
>>> для i в (
... 40,
... dict (foo = 1, bar = 2),
... {1, 2, 3},
... 'бар',
... ['foo', 'bar', 'baz']):
... f (я)
... печать (я)
...
40
{'foo': 1, 'bar': 2}
{1, 2, 3}
бар
['фу', 'бар', 'баз']
Здесь объекты типа int
, dict
, set
, str
и list
передаются в f ()
в качестве аргументов. f ()
пытается назначить каждый объект строковому объекту 'foo'
, но, как вы можете видеть, вернувшись в вызывающую среду, все они не изменились.Как только f ()
выполнит присвоение x = 'foo'
, ссылка будет rebound , и соединение с исходным объектом будет потеряно.
Означает ли это, что функция Python вообще никогда не может изменять свои аргументы? На самом деле нет, это не так! Посмотрите, что здесь происходит:
>>>
>>> def f (x):
... x [0] = '---'
...
>>> my_list = ['foo', 'bar', 'baz', 'qux']
>>> f (мой_лист)
>>> мой_лист
['---', 'bar', 'baz', 'qux']
В этом случае аргумент f ()
является списком.Когда вызывается f ()
, передается ссылка на my_list
. Вы уже видели, что f ()
не может переназначить my_list
оптом. Если бы x
было назначено чему-то другому, то он был бы привязан к другому объекту, и соединение с my_list
было потеряно.
Однако f ()
может использовать ссылку для внесения изменений в my_list
. Здесь f ()
модифицировал первый элемент.Вы можете видеть, что после возврата из функции my_list
фактически был изменен в вызывающей среде. То же самое относится и к словарю:
>>>
>>> def f (x):
... x ['bar'] = 22
...
>>> my_dict = {'foo': 1, 'bar': 2, 'baz': 3}
>>> f (my_dict)
>>> my_dict
{'foo': 1, 'bar': 22, 'baz': 3}
Здесь f ()
использует x
в качестве ссылки для внесения изменений в my_dict
.Это изменение отражается в вызывающей среде после возврата f ()
.
Сводка по передаче аргументов
Передачу аргумента в Python можно резюмировать следующим образом. Передача неизменяемого объекта , такого как int
, str
, кортеж
или frozenset
, в функцию Python действует как передача по значению. Функция не может изменять объект в вызывающей среде.
Передача изменяемого объекта , такого как список
, dict
или set
, действует в некоторой степени — но не совсем — как передача по ссылке.Функция не может переназначить объект оптом, но она может изменять элементы на месте внутри объекта, и эти изменения будут отражены в вызывающей среде.
Побочные эффекты
Итак, в Python вы можете изменить аргумент из функции, чтобы изменение отражалось в вызывающей среде. Но стоит ли вам это делать? Это пример того, что на жаргоне программирования называется побочным эффектом .
В более общем смысле говорят, что функция Python вызывает побочный эффект, если она каким-либо образом изменяет среду своего вызова.Изменение значения аргумента функции — лишь одна из возможностей.
Примечание: Вы, вероятно, знакомы с побочными эффектами из области здоровья человека, где этот термин обычно относится к непреднамеренным последствиям приема лекарств. Часто последствия нежелательны, например, рвота или седативный эффект. С другой стороны, побочные эффекты можно использовать намеренно. Например, некоторые лекарства вызывают стимуляцию аппетита, что может быть полезно, даже если это не является основным назначением лекарства.
Концепция аналогична в программировании. Если побочный эффект является хорошо задокументированной частью спецификации функции, и пользователь функции четко знает, когда и как вызывающая среда может быть изменена, тогда все в порядке. Но программист не всегда может должным образом документировать побочные эффекты или даже не подозревать о возникновении побочных эффектов.
Когда они скрыты или неожиданны, побочные эффекты могут привести к программным ошибкам, которые очень трудно отследить.Как правило, их лучше избегать.
Возврат
Отчет
Что тогда делать функции Python? В конце концов, во многих случаях, если функция не вызывает каких-либо изменений в вызывающей среде, тогда нет никакого смысла в ее вызове. Как функция должна влиять на вызывающего?
Ну, одна из возможностей — использовать значение , возвращаемое функцией . Оператор return
в функции Python служит двум целям:
- Он немедленно завершает функцию и передает управление выполнением обратно вызывающей стороне.
- Он предоставляет механизм, с помощью которого функция может передавать данные обратно вызывающей стороне.
Выход из функции
Внутри функции оператор return
вызывает немедленный выход из функции Python и передачу выполнения обратно вызывающей стороне:
>>>
>>> def f ():
... печать ('фу')
... печать ('полоса')
... возвращаться
...
>>> f ()
фу
бар
В этом примере оператор return
фактически лишний.Функция вернется к вызывающему, когда упадет с конца , то есть после выполнения последнего оператора тела функции. Таким образом, эта функция будет вести себя идентично без оператора return
.
Однако возвращает
операторов не обязательно в конце функции. Они могут появляться в любом месте тела функции и даже несколько раз. Рассмотрим этот пример:
>>>
1 >>> def f (x):
2 ... если x <0:
3... возвращаться
4 ... если x> 100:
5 ... вернуться
6 ... печать (x)
7 ...
8
9 >>> f (-3)
10 >>> f (105)
11 >>> f (64)
1264
Первые два вызова f ()
не вызывают никакого вывода, потому что выполняется оператор return
и функция завершается преждевременно, до того, как будет достигнут оператор print ()
в строке 6.
Такая парадигма может быть полезна для проверки ошибок в функции. Вы можете проверить несколько условий ошибки в начале функции, с помощью возврата
операторов, которые выручают, если есть проблема:
def f ():
если error_cond1:
возвращаться
если error_cond2:
возвращаться
если error_cond3:
возвращаться
<нормальная обработка>
Если ни одно из условий ошибки не обнаружено, функция может продолжить свою обычную обработку.
Возврат данных вызывающему абоненту
Помимо выхода из функции, оператор return
также используется для передачи данных обратно вызывающему . Если за оператором return
внутри функции Python следует выражение, то в вызывающей среде вызов функции оценивается как значение этого выражения:
>>>
1 >>> def f ():
2 ... вернуть 'foo'
3 ...
4
5 >>> s = f ()
6 >>> с
7'фу '
Здесь значение выражения f ()
в строке 5 равно 'foo'
, которое впоследствии присваивается переменной s
.
Функция может возвращать любой тип объекта . В Python это означает что угодно. В вызывающей среде вызов функции может использоваться синтаксически любым способом, который имеет смысл для типа объекта, который возвращает функция.
Например, в этом коде f ()
возвращает словарь. Тогда в вызывающей среде выражение f ()
представляет словарь, а f () ['baz']
является действительной ключевой ссылкой в этот словарь:
>>>
>>> def f ():
... return dict (foo = 1, bar = 2, baz = 3)
...
>>> f ()
{'foo': 1, 'bar': 2, 'baz': 3}
>>> f () ['баз']
3
В следующем примере f ()
возвращает строку, которую можно разрезать, как любую другую строку:
>>>
>>> def f ():
... вернуть 'foobar'
...
>>> f () [2: 4]
'ob'
Здесь f ()
возвращает список, который можно индексировать или разрезать:
>>>
>>> def f ():
... return ['foo', 'bar', 'baz', 'qux']
...
>>> f ()
['foo', 'bar', 'baz', 'qux']
>>> f () [2]
'баз'
>>> f () [:: - 1]
['qux', 'baz', 'bar', 'foo']
Если в инструкции return
указано несколько выражений, разделенных запятыми, они упаковываются и возвращаются как кортеж:
>>>
>>> def f ():
... вернуть 'foo', 'bar', 'baz', 'qux'
...
>>> тип (f ())
<класс 'кортеж'>
>>> t = f ()
>>> т
('foo', 'bar', 'baz', 'qux')
>>> a, b, c, d = f ()
>>> print (f'a = {a}, b = {b}, c = {c}, d = {d} ')
a = foo, b = bar, c = baz, d = qux
Если возвращаемое значение не указано, функция Python возвращает специальное значение Python Нет
:
>>>
>>> def f ():
... возвращаться
...
>>> print (f ())
Никто
То же самое происходит, если тело функции вообще не содержит оператора return
и функция падает с конца:
>>>
>>> def g ():
... проходить
...
>>> print (g ())
Никто
Напомним, что Нет
является ложным при оценке в логическом контексте.
Так как функции, которые выходят с помощью простого оператора , возвращают
или падают в конце, возвращают Нет
, вызов такой функции может использоваться в логическом контексте:
>>>
>>> def f ():
... возвращаться
...
>>> def g ():
... проходить
...
>>> если f () или g ():
... печать ('да')
... еще:
... печать ('нет')
...
нет
Здесь вызовы как f (),
, так и g ()
являются ложными, поэтому f () или g ()
также являются ложными, и выполняется предложение else
.
Возвращаясь к побочным эффектам
Предположим, вы хотите написать функцию, которая принимает целочисленный аргумент и удваивает его. То есть вы хотите передать целочисленную переменную в функцию, и когда функция вернется, значение переменной в вызывающей среде должно быть вдвое больше, чем было.В Паскале это можно сделать с помощью передачи по ссылке:
1процедура double (var x: integer);
2начать
3 х: = х * 2;
4end;
5
6вар
7 x: целое число;
8
9начало
10 х: = 5;
11 Writeln ('Перед вызовом процедуры:', x);
12 двойных (х);
13 Writeln ('После вызова процедуры:', x);
14 конец.
Выполнение этого кода дает следующий результат, который подтверждает, что double ()
действительно изменяет x
в вызывающей среде:
Перед процедурой вызов: 5
После вызова процедуры: 10
В Python это не сработает.Как вы теперь знаете, целые числа Python неизменяемы, поэтому функция Python не может изменить целочисленный аргумент с помощью побочного эффекта:
>>>
>>> def double (x):
... х * = 2
...
>>> х = 5
>>> двойной (х)
>>> х
5
Однако вы можете использовать возвращаемое значение для получения аналогичного эффекта. Просто напишите double ()
, чтобы он принимал целочисленный аргумент, удваивал его и возвращал удвоенное значение. Затем вызывающий абонент отвечает за присвоение, изменяющее исходное значение:
>>>
>>> def double (x):
... вернуть x * 2
...
>>> х = 5
>>> х = двойной (х)
>>> х
10
Возможно, это предпочтительнее модификации с помощью побочного эффекта. Совершенно очевидно, что x
изменяется в вызывающей среде, потому что вызывающий делает это сам. В любом случае, это единственный вариант, потому что модификация с помощью побочного эффекта в этом случае не работает.
Тем не менее, даже в тех случаях, когда можно изменить аргумент с помощью побочного эффекта, использование возвращаемого значения может быть более ясным.Предположим, вы хотите удвоить каждый элемент в списке. Поскольку списки изменяемы, вы можете определить функцию Python, которая изменяет список на месте:
>>>
>>> def double_list (x):
... я = 0
... пока я >> a = [1, 2, 3, 4, 5]
>>> double_list (а)
>>> а
[2, 4, 6, 8, 10]
В отличие от double ()
в предыдущем примере, double_list ()
фактически работает так, как задумано.Если в документации для функции четко указано, что содержимое аргумента списка изменено, это может быть разумной реализацией.
Тем не менее, вы также можете написать double_list ()
, чтобы передать желаемый список обратно по возвращаемому значению и позволить вызывающей стороне выполнить назначение, аналогично тому, как double ()
был переписан в предыдущем примере:
>>>
>>> def double_list (x):
... r = []
... для i в x:
... р.добавить (я * 2)
... вернуть г
...
>>> a = [1, 2, 3, 4, 5]
>>> а = двойной_лист (а)
>>> а
[2, 4, 6, 8, 10]
Оба подхода работают одинаково хорошо. Как это часто бывает, это вопрос стиля и личных предпочтений. Побочные эффекты не обязательно являются абсолютным злом, и они имеют свое место, но поскольку практически все может быть возвращено из функции, то же самое обычно можно достичь и с помощью возвращаемых значений.
Списки аргументов переменной длины
В некоторых случаях, когда вы определяете функцию, вы можете не знать заранее, сколько аргументов вы хотите, чтобы она принимала.Предположим, например, что вы хотите написать функцию Python, которая вычисляет среднее нескольких значений. Начать можно примерно так:
>>>
>>> def avg (a, b, c):
... return (a + b + c) / 3
...
Все хорошо, если вы хотите усреднить три значения:
Однако, как вы уже видели, когда используются позиционные аргументы, количество переданных аргументов должно соответствовать количеству объявленных параметров. Тогда ясно, что с этой реализацией avg ()
для любого количества значений, кроме трех, не все в порядке:
>>>
>>> ср (1, 2, 3, 4)
Отслеживание (последний вызов последний):
Файл "", строка 1, в
средн. (1, 2, 3, 4)
TypeError: avg () принимает 3 позиционных аргумента, но было дано 4
Вы можете попробовать определить avg ()
с дополнительными параметрами:
>>>
>>> def avg (a, b = 0, c = 0, d = 0, e = 0):
....
....
....
...
Это позволяет указывать переменное количество аргументов. Следующие вызовы, по крайней мере, синтаксически верны:
в среднем (1)
ср (1, 2)
средн. (1, 2, 3)
средн. (1, 2, 3, 4)
средн. (1, 2, 3, 4, 5)
Но при таком подходе все еще есть несколько проблем. Во-первых, он по-прежнему позволяет использовать до пяти аргументов, а не произвольное число. Что еще хуже, нет способа отличить указанные аргументы от аргументов, которым разрешено использовать по умолчанию.У функции нет способа узнать, сколько аргументов было фактически передано, поэтому она не знает, на что делить:
>>>
>>> def avg (a, b = 0, c = 0, d = 0, e = 0):
... return (a + b + c + d + e) / # На что делить ???
...
Очевидно, и этого не пойдет.
Вы можете написать avg ()
, чтобы получить единственный аргумент списка:
>>>
>>> def avg (a):
... всего = 0
... для v в:
... всего + = v
... return total / len (a)
...
>>> avg ([1, 2, 3])
2.0
>>> avg ([1, 2, 3, 4, 5])
3.0
По крайней мере, это работает. Он допускает произвольное количество значений и дает правильный результат. В качестве дополнительного бонуса это работает, когда аргумент также является кортежем:
>>>
>>> t = (1, 2, 3, 4, 5)
>>> avg (t)
3.0
Недостатком является то, что дополнительный этап группировки значений в список или кортеж, вероятно, не является тем, чего ожидает пользователь функции, и это не очень элегантно.Всякий раз, когда вы находите код Python, который выглядит неэлегантно, вероятно, есть лучший вариант.
В данном случае действительно есть! Python предоставляет способ передать функции переменное количество аргументов с упаковкой и распаковкой кортежа аргументов с помощью оператора звездочки ( *
).
Упаковка кортежей аргументов
Если перед именем параметра в определении функции Python стоит звездочка ( *
), это означает, что упаковка кортежа аргументов . Все соответствующие аргументы в вызове функции упаковываются в кортеж, на который функция может ссылаться по заданному имени параметра.Вот пример:
>>>
>>> def f (* args):
... печать (аргументы)
... print (тип (аргументы), len (аргументы))
... для x в аргументах:
... печать (x)
...
>>> f (1, 2, 3)
(1, 2, 3)
<класс 'кортеж'> 3
1
2
3
>>> f ('foo', 'bar', 'baz', 'qux', 'quux')
('foo', 'bar', 'baz', 'qux', 'quux')
<класс 'кортеж'> 5
фу
бар
баз
qux
quux
В определении f ()
спецификация параметра * args
указывает на упаковку кортежа.При каждом вызове f ()
аргументы упаковываются в кортеж, на который функция может ссылаться по имени args
. Можно использовать любое имя, но args
выбирают настолько часто, что это практически стандарт.
Используя упаковку кортежей, вы можете очистить avg ()
следующим образом:
>>>
>>> def avg (* args):
... всего = 0
... для i в аргументах:
... всего + = я
... вернуть total / len (args)
...
>>> avg (1, 2, 3)
2.0
>>> avg (1, 2, 3, 4, 5)
3.0
Более того, вы можете привести его в порядок, заменив цикл на
на встроенную функцию Python sum ()
, которая суммирует числовые значения в любой итерации:
>>>
>>> def avg (* args):
... вернуть сумму (аргументы) / len (аргументы)
...
>>> avg (1, 2, 3)
2.0
>>> avg (1, 2, 3, 4, 5)
3.0
Теперь avg ()
написан лаконично и работает по назначению.
Тем не менее, в зависимости от того, как этот код будет использоваться, может быть, еще есть над чем поработать. Как написано, avg ()
выдаст исключение TypeError
, если какие-либо аргументы не являются числовыми:
>>>
>>> avg (1, 'foo', 3)
Отслеживание (последний вызов последний):
Файл "", строка 1, в
Файл "", строка 2, в среднем
TypeError: неподдерживаемые типы операндов для +: 'int' и 'str'
Для максимальной надежности следует добавить код, проверяющий, что аргументы имеют правильный тип.Позже в этой серии руководств вы узнаете, как перехватывать исключения, такие как TypeError
, и обрабатывать их соответствующим образом. Вы также можете проверить исключения Python: Введение.
Распаковка кортежа аргументов
Аналогичная операция доступна на другой стороне уравнения в вызове функции Python. Когда аргументу в вызове функции предшествует звездочка ( *
), это указывает на то, что аргумент является кортежем, который должен быть распакован, и передан в функцию как отдельные значения:
>>>
>>> def f (x, y, z):
... print (f'x = {x} ')
... печать (f'y = {y} ')
... печать (f'z = {z} ')
...
>>> f (1, 2, 3)
х = 1
у = 2
г = 3
>>> t = ('фу', 'бар', 'баз')
>>> f (* t)
x = foo
y = бар
z = baz
В этом примере * t
в вызове функции указывает, что t
— это кортеж, который следует распаковать. Распакованные значения 'foo'
, 'bar'
и 'baz'
назначаются параметрам x
, y
и z
соответственно.
Хотя этот тип распаковки называется распаковкой кортежей , он работает не только с кортежами. Оператор звездочки ( *
) может применяться к любой итерации в вызове функции Python. Например, список или набор тоже можно распаковать:
>>>
>>> a = ['foo', 'bar', 'baz']
>>> тип (а)
<список классов>
>>> f (* а)
x = foo
y = бар
z = baz
>>> s = {1, 2, 3}
>>> тип (ы)
<класс 'набор'>
>>> f (* s)
х = 1
у = 2
г = 3
Вы даже можете использовать упаковку и распаковку кортежей одновременно:
>>>
>>> def f (* args):
... print (тип (аргументы), аргументы)
...
>>> a = ['foo', 'bar', 'baz', 'qux']
>>> f (* а)
<класс 'кортеж'> ('foo', 'bar', 'baz', 'qux')
Здесь f (* a)
указывает, что список a
должен быть распакован, а элементы переданы в f ()
как отдельные значения. Спецификация параметра * args
заставляет значения упаковываться обратно в кортеж args
.
Упаковка словаря аргументов
Python имеет аналогичный оператор, двойную звездочку ( **
), который можно использовать с параметрами и аргументами функции Python для указания упаковки и распаковки словаря .Двойная звездочка ( **
) перед параметром в определении функции Python указывает на то, что соответствующие аргументы, которые, как ожидается, будут парами ключ = значение
, должны быть упакованы в словарь:
>>>
>>> def f (** kwargs):
... печать (kwargs)
... print (введите (kwargs))
... для ключа val в kwargs.items ():
... print (ключ, '->', val)
...
>>> f (foo = 1, bar = 2, baz = 3)
{'foo': 1, 'bar': 2, 'baz': 3}
<класс 'dict'>
foo -> 1
бар -> 2
баз -> 3
В этом случае аргументы foo = 1
, bar = 2
и baz = 3
упаковываются в словарь, на который функция может ссылаться по имени kwargs
.Опять же, можно использовать любое имя, но своеобразное kwargs
(сокращение от ключевого слова args ) почти стандартно. Вам не обязательно его придерживаться, но если вы это сделаете, то любой, кто знаком с соглашениями о кодировании Python, сразу поймет, что вы имеете в виду.
Распаковка словаря аргументов
Распаковка словаря аргументов аналогична распаковке кортежа аргументов. Когда двойная звездочка ( **
) предшествует аргументу в вызове функции Python, это указывает, что аргумент является словарем, который следует распаковать, с полученными элементами, переданными в функцию как аргументы ключевого слова:
>>>
>>> def f (a, b, c):
... print (F'a = {a} ')
... печать (F'b = {b} ')
... печать (F'c = {c} ')
...
>>> d = {'a': 'foo', 'b': 25, 'c': 'qux'}
>>> е (** д)
a = foo
б = 25
c = qux
Элементы в словаре d
распаковываются и передаются в f ()
как аргументы ключевого слова. Итак, f (** d)
эквивалентно f (a = 'foo', b = 25, c = 'qux')
:
>>>
>>> f (a = 'foo', b = 25, c = 'qux')
a = foo
б = 25
c = qux
На самом деле, проверьте это:
>>>
>>> f (** dict (a = 'foo', b = 25, c = 'qux'))
a = foo
б = 25
c = qux
Здесь dict (a = 'foo', b = 25, c = 'qux')
создает словарь из указанных пар ключ / значение.Затем оператор двойной звездочки ( **
) распаковывает его и передает ключевые слова в f ()
.
Собираем все вместе
Думайте о * args
как о списке позиционных аргументов переменной длины, а о ** kwargs
как о списке аргументов ключевого слова переменной длины.
Все три — стандартные позиционные параметры, * args
и ** kwargs
— могут использоваться в одном определении функции Python. Если да, то их следует указывать в таком порядке:
>>>
>>> def f (a, b, * args, ** kwargs):
... print (F'a = {a} ')
... печать (F'b = {b} ')
... print (F'args = {args} ')
... печать (F'kwargs = {kwargs} ')
...
>>> f (1, 2, 'foo', 'bar', 'baz', 'qux', x = 100, y = 200, z = 300)
а = 1
b = 2
args = ('foo', 'bar', 'baz', 'qux')
kwargs = {'x': 100, 'y': 200, 'z': 300}
Это обеспечивает столько гибкости, сколько вам может понадобиться в функциональном интерфейсе!
Множественные распаковки в вызове функции Python
Python версии 3.5 представил поддержку дополнительных обобщений распаковки, как указано в PEP 448.Одна вещь, которую позволяют эти улучшения, — это несколько распаковок за один вызов функции Python:
>>>
>>> def f (* args):
... для i в аргументах:
... печать (я)
...
>>> a = [1, 2, 3]
>>> t = (4, 5, 6)
>>> s = {7, 8, 9}
>>> f (* a, * t, * s)
1
2
3
4
5
6
8
9
7
Вы также можете указать несколько распаковок словарей в вызове функции Python:
>>>
>>> def f (** kwargs):
... для k, v в kwargs.items ():
... print (k, '->', v)
...
>>> d1 = {'a': 1, 'b': 2}
>>> d2 = {'x': 3, 'y': 4}
>>> f (** d1, ** d2)
а -> 1
б -> 2
х -> 3
у -> 4
Примечание: Это расширение доступно только в Python версии 3.5 или новее. Если вы попробуете это в более ранней версии, то получите исключение SyntaxError
.
Кстати, операторы распаковки *
и **
применяются не только к переменным, как в примерах выше.Вы также можете использовать их с литералами, которые повторяются:
>>>
>>> def f (* args):
... для i в аргументах:
... печать (я)
...
>>> f (* [1, 2, 3], * [4, 5, 6])
1
2
3
4
5
6
>>> def f (** kwargs):
... для k, v в kwargs.items ():
... print (k, '->', v)
...
>>> f (** {'a': 1, 'b': 2}, ** {'x': 3, 'y': 4})
а -> 1
б -> 2
х -> 3
у -> 4
Здесь литеральные списки [1, 2, 3]
и [4, 5, 6]
указаны для распаковки кортежей, а буквальные словари {'a': 1, 'b': 2}
и {'x': 3, 'y': 4}
указаны для распаковки словаря.
Аргументы только для ключевых слов
Функцию Python в версии 3.x можно определить так, чтобы она принимала аргументов, содержащих только ключевые слова. . Это аргументы функции, которые должны быть указаны с помощью ключевого слова. Давайте рассмотрим ситуацию, в которой это может быть полезно.
Предположим, вы хотите написать функцию Python, которая принимает переменное количество строковых аргументов, объединяет их вместе, разделенные точкой ( "."
), и выводит их на консоль. Для начала подойдет что-то вроде этого:
>>>
>>> def concat (* args):
... print (f '-> {".". join (args)}')
...
>>> concat ('a', 'b', 'c')
-> a.b.c
>>> concat ('foo', 'bar', 'baz', 'qux').
-> foo.bar.baz.qux
В существующем виде выходной префикс жестко запрограммирован на строку '->'
. Что, если вы хотите изменить функцию, чтобы она также принимала это как аргумент, чтобы пользователь мог указать что-то еще? Это одна возможность:
>>>
>>> def concat (префикс, * args):
... print (f '{prefix} {".".join (аргументы)} ')
...
>>> concat ('//', 'a', 'b', 'c')
//a.b.c
>>> concat ('...', 'foo', 'bar', 'baz', 'qux')
... foo.bar.baz.qux
Это работает так, как рекламируется, но в этом решении есть несколько нежелательных моментов:
Строка префикса
префикс
не является обязательным. Его всегда нужно включать, и нет возможности принять значение по умолчанию.
Вы могли подумать, что можете решить вторую проблему, указав параметр со значением по умолчанию, например, например:
>>>
>>> def concat (prefix = '->', * args):
... print (f '{префикс} {".". join (args)}')
...
К сожалению, это работает не совсем правильно. Префикс
— это позиционный параметр , поэтому интерпретатор предполагает, что первый аргумент, указанный в вызове функции, является предполагаемым выходным префиксом.Это означает, что его нельзя пропустить и получить значение по умолчанию:
.
>>>
>>> concat ('a', 'b', 'c')
ab.c
Что если вы попытаетесь указать префикс
в качестве аргумента ключевого слова? Ну, вы не можете сначала указать это:
>>>
>>> concat (prefix = '//', 'a', 'b', 'c')
Файл "", строка 1
SyntaxError: позиционный аргумент следует за аргументом ключевого слова
Как вы видели ранее, когда даны оба типа аргументов, все позиционные аргументы должны стоять перед любыми аргументами ключевого слова.
Однако вы также не можете указать его последним:
>>>
>>> concat ('a', 'b', 'c', prefix = '...')
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: concat () получил несколько значений для аргумента prefix
Опять же, префикс
является позиционным параметром, поэтому ему назначается первый аргумент, указанный в вызове (в данном случае это 'a'
). Затем, когда он снова указывается в качестве аргумента ключевого слова в конце, Python думает, что он был назначен дважды.
Параметры только для ключевых слов помогают решить эту дилемму. В определении функции укажите * args
, чтобы указать переменное количество позиционных аргументов, а затем укажите префикс после этого
:
>>>
>>> def concat (* args, prefix = '->'):
... print (f '{префикс} {".". join (args)}')
...
В этом случае префикс
становится параметром только с ключевым словом. Его значение никогда не будет заполнено позиционным аргументом.Его можно указать только с помощью именованного аргумента ключевого слова:
>>>
>>> concat ('a', 'b', 'c', prefix = '...')
... a.b.c
Обратите внимание, что это возможно только в Python 3. В версии 2.x Python указание дополнительных параметров после параметра аргументов переменной * args
вызывает ошибку.
Аргументы, содержащие только ключевое слово, позволяют функции Python принимать переменное количество аргументов, за которыми следует одна или несколько дополнительных опций в качестве аргументов ключевого слова.Если вы хотите изменить concat ()
так, чтобы можно было указать символ-разделитель, вы можете добавить дополнительный аргумент, состоящий только из ключевых слов:
>>>
>>> def concat (* args, prefix = '->', sep = '.'):
... print (f '{префикс} {sep.join (args)}')
...
>>> concat ('a', 'b', 'c')
-> a.b.c
>>> concat ('a', 'b', 'c', prefix = '//')
//a.b.c
>>> concat ('a', 'b', 'c', prefix = '//', sep = '-')
// а-б-в
Если параметру, содержащему только ключевое слово, присвоено значение по умолчанию в определении функции (как в приведенном выше примере), а ключевое слово опущено при вызове функции, то предоставляется значение по умолчанию:
>>>
>>> concat ('a', 'b', 'c')
-> а.до н.э
Если, с другой стороны, параметру не присвоено значение по умолчанию, то он становится обязательным, и если его не указать, возникает ошибка:
>>>
>>> def concat (* args, префикс):
... print (f '{префикс} {".". join (args)}')
...
>>> concat ('a', 'b', 'c', prefix = '...')
... a.b.c
>>> concat ('a', 'b', 'c')
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: в concat () отсутствует 1 обязательный аргумент, содержащий только ключевое слово: 'prefix'
Что, если вы хотите определить функцию Python, которая принимает аргумент, состоящий только из ключевых слов, но не принимает переменное количество позиционных аргументов? Например, следующая функция выполняет указанную операцию с двумя числовыми аргументами:
>>>
>>> def oper (x, y, op = '+'):
... если op == '+':
... вернуть x + y
... elif op == '-':
... вернуть x - y
... elif op == '/':
... вернуть x / y
... еще:
... return None
...
>>> опер (3, 4)
7
>>> опер (3, 4, '+')
7
>>> опер (3, 4, '/')
0,75
Если вы хотите сделать op
параметром только для ключевого слова, вы можете добавить посторонний параметр аргумента фиктивной переменной и просто игнорировать его:
>>>
>>> def oper (x, y, * ignore, op = '+'):
... если op == '+':
... вернуть x + y
... elif op == '-':
... вернуть x - y
... elif op == '/':
... вернуть x / y
... еще:
... return None
...
>>> oper (3, 4, op = '+')
7
>>> oper (3, 4, op = '/')
0,75
Проблема с этим решением заключается в том, что * ignore
поглощает любые посторонние позиционные аргументы, которые могут быть включены:
>>>
>>> oper (3, 4, «Мне здесь не место»)
7
>>> oper (3, 4, «Мне здесь не место», op = '/')
0.75
В этом примере не должно быть дополнительного аргумента (как объявляет сам аргумент). Вместо того, чтобы тихо добиться успеха, это действительно должно привести к ошибке. То, что это не так, в лучшем случае неопрятно. В худшем случае это может привести к вводящему в заблуждение результату:
Чтобы исправить это, версия 3 позволяет параметру аргумента переменной в определении функции Python быть просто звездочкой ( *
) с опущенным именем:
>>>
>>> def oper (x, y, *, op = '+'):
... если op == '+':
... вернуть x + y
... elif op == '-':
... вернуть x - y
... elif op == '/':
... вернуть x / y
... еще:
... return None
...
>>> oper (3, 4, op = '+')
7
>>> oper (3, 4, op = '/')
0,75
>>> oper (3, 4, «Мне здесь не место»)
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: oper () принимает 2 позиционных аргумента, но было дано 3
>>> опер (3, 4, '+')
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: oper () принимает 2 позиционных аргумента, но было дано 3
Параметр простого переменного аргумента *
указывает, что больше нет никаких позиционных параметров.Это поведение генерирует соответствующие сообщения об ошибках, если указаны дополнительные. Он позволяет следовать параметрам, содержащим только ключевые слова.
Только позиционные аргументы
Начиная с Python 3.8, параметры функции также могут быть объявлены только позиционно , то есть соответствующие аргументы должны быть предоставлены позиционно и не могут быть указаны с помощью ключевого слова.
Чтобы обозначить некоторые параметры как позиционные, вы указываете косую черту (/
) в списке параметров определения функции.Все параметры слева от косой черты (/
) должны быть указаны позиционно. Например, в следующем определении функции x
и y
являются позиционными параметрами, но z
можно указать с помощью ключевого слова:
>>>
>>> # Это Python 3.8
>>> def f (x, y, /, z):
... print (f'x: {x} ')
... print (f'y: {y} ')
... print (f'z: {z} ')
...
Это означает, что действительны следующие вызовы:
>>>
>>> f (1, 2, 3)
х: 1
г: 2
z: 3
>>> f (1, 2, z = 3)
х: 1
г: 2
z: 3
Однако следующий звонок на номер f ()
недействителен:
>>>
>>> f (x = 1, y = 2, z = 3)
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: f () получила некоторые позиционные аргументы, переданные как аргументы ключевого слова:
'х, у'
Позиционные указатели и указатели только для ключевых слов могут использоваться в одном и том же определении функции:
>>>
>>> # Это Python 3.8
>>> def f (x, y, /, z, w, *, a, b):
... print (x, y, z, w, a, b)
...
>>> f (1, 2, z = 3, w = 4, a = 5, b = 6)
1 2 3 4 5 6
>>> f (1, 2, 3, w = 4, a = 5, b = 6)
1 2 3 4 5 6
В этом примере:
-
x
иy
являются только позиционными. -
a
иb
— только ключевые слова. -
z
иw
можно указать позиционно или по ключевому слову.
Для получения дополнительной информации о позиционных параметрах см. Основные моменты выпуска Python 3.8.
Строки документов
Когда первая инструкция в теле функции Python является строковым литералом, она называется строкой документации функции . Строка документации используется для предоставления документации для функции. Он может содержать назначение функции, аргументы, которые она принимает, информацию о возвращаемых значениях или любую другую информацию, которая, по вашему мнению, будет полезной.
Ниже приведен пример определения функции со строкой документации:
>>>
>>> def avg (* args):
... "" "Возвращает среднее значение списка числовых значений." ""
... вернуть сумму (аргументы) / len (аргументы)
...
Технически, строки документации могут использовать любой из механизмов цитирования Python, но рекомендуется использовать тройную кавычку с использованием символов двойных кавычек ( "" "
), как показано выше. Если строка документации умещается в одной строке, то котировки закрытия должны находиться на той же строке, что и котировки открытия.
Многострочные строки документации используются для более объемной документации.Многострочная строка документации должна состоять из итоговой строки, за которой следует пустая строка, за которой следует более подробное описание. Котировки закрытия должны быть на отдельной строке:
>>>
>>> def foo (bar = 0, baz = 1):
... "" "Выполните преобразование foo.
...
... Аргументы ключевого слова:
... bar - величина по оси бара (по умолчанию = 0)
... baz - величина по оси baz (по умолчанию = 1)
... "" "
...
...
Форматирование строки документации и семантические соглашения подробно описаны в PEP 257.
Когда определена строка документации, интерпретатор Python назначает ее специальному атрибуту функции с именем __doc__
. Этот атрибут является одним из набора специализированных идентификаторов в Python, которые иногда называют магическими атрибутами или магическими методами , потому что они предоставляют специальные языковые функции.
Примечание: Эти атрибуты также упоминаются с помощью атрибутов dunder с красочным псевдонимом и методов dunder. Слово dunder объединяет d из двойных и под из символа подчеркивания ( _
).В будущих уроках этой серии вы встретите еще много неприятных атрибутов и методов.
Вы можете получить доступ к строке документации функции с помощью выражения
. Строки документации для приведенных выше примеров могут отображаться следующим образом:
>>>
>>> print (ср .__ doc__)
Возвращает среднее значение списка числовых значений.
>>> печать (foo .__ doc__)
Выполните преобразование foo.
Аргументы ключевого слова:
bar - величина по оси бара (по умолчанию = 0)
baz - величина по оси baz (по умолчанию = 1)
В интерактивном интерпретаторе Python вы можете ввести help (
, чтобы отобразить строку документации для
:
>>>
>>> справка (средн.)
Справка по функции avg в модуле __main__:
avg (* аргументы)
Возвращает среднее значение списка числовых значений.>>> help (foo)
Справка по функции foo в модуле __main__:
foo (bar = 0, baz = 1)
Выполните преобразование foo.
Аргументы ключевого слова:
bar - величина по оси бара (по умолчанию = 0)
baz - величина по оси baz (по умолчанию = 1)
Считается хорошей практикой кодирования указывать строку документации для каждой определяемой вами функции Python. Дополнительные сведения о строках документации см. В документе «Документирование кода Python: полное руководство».
Аннотации функций Python
Начиная с версии 3.0, Python предоставляет дополнительную функцию для документирования функции, называемую аннотацией функции . Аннотации позволяют прикреплять метаданные к параметрам функции и возвращаемому значению.
Чтобы добавить аннотацию к параметру функции Python, вставьте двоеточие (:
), за которым следует любое выражение после имени параметра в определении функции. Чтобы добавить аннотацию к возвращаемому значению, добавьте символы ->
и любое выражение между закрывающей круглой скобкой списка параметров и двоеточием, завершающим заголовок функции.Вот пример:
>>>
>>> def f (a: '', b: '') -> '':
... проходить
...
Аннотация для параметра a
— это строка ''
, для b
строка ''
, а для возвращаемого значения функции строка '
.
Интерпретатор Python создает словарь из аннотаций и назначает их другому специальному атрибуту dunder функции __annotations__
.Аннотации для функции Python f ()
, показанные выше, могут отображаться следующим образом:
>>>
>>> f .__ annotations__
{'a': '', 'b': '', 'return': ''}
Ключи для параметров — это имена параметров. Ключом для возвращаемого значения является строка return
:
.
>>>
>>> f .__ annotations __ ['a']
""
>>> f .__ аннотации __ ['b']
''
>>> е.__annotations __ ['return']
''
Обратите внимание, что аннотации не ограничиваются строковыми значениями. Это может быть любое выражение или объект. Например, вы можете аннотировать объекты типа:
>>>
>>> def f (a: int, b: str) -> float:
... print (a, b)
... вернуть (3.5)
...
>>> f (1, 'фу')
1 фу
3.5
>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
Аннотация может быть даже составным объектом, например списком или словарем, поэтому к параметрам и возвращаемому значению можно прикрепить несколько элементов метаданных:
>>>
>>> def area (
... р: {
... 'desc': 'радиус круга',
... 'тип': float
...}) -> \
... {
... 'desc': 'площадь круга',
... 'тип': float
...}:
... return 3.14159 * (r ** 2)
...
>>> площадь (2,5)
19,6349375
>>> area .__ annotations__
{'r': {'desc': 'радиус круга', 'type': },
'return': {'desc': 'область круга', 'type': }}
>>> area .__ annotations __ ['r'] ['desc']
'радиус круга'
>>> Площадь.__annotations __ ['return'] ['type']
<класс 'float'>
В приведенном выше примере аннотация прикреплена к параметру r
и к возвращаемому значению. Каждая аннотация представляет собой словарь, содержащий описание строки и объект типа.
Если вы хотите присвоить значение по умолчанию параметру, имеющему аннотацию, то значение по умолчанию идет после аннотации:
>>>
>>> def f (a: int = 12, b: str = 'baz') -> float:
... print (a, b)
... вернуть (3.5)
...
>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
>>> f ()
12 баз
3.5
Что делают аннотации? Откровенно говоря, они почти ничего не делают. Они просто вроде как там. Давайте снова посмотрим на один из приведенных выше примеров, но с небольшими изменениями:
>>>
>>> def f (a: int, b: str) -> float:
... print (a, b)
... вернуть 1, 2, 3
...
>>> f ('фу', 2,5)
foo 2.5
(1, 2, 3)
Что здесь происходит? Аннотации для f ()
указывают, что первый аргумент — int
, второй аргумент — str
, а возвращаемое значение — float
. Но последующий вызов f ()
нарушает все правила! Аргументы: str
и float
соответственно, а возвращаемое значение — кортеж. И все же переводчик позволяет всему этому скользить без каких-либо жалоб.
Аннотации не накладывают никаких семантических ограничений на код вообще. Это просто биты метаданных, прикрепленные к параметрам функции Python и возвращаемому значению. Python послушно прячет их в словаре, присваивает словарю атрибут dunder функции __annotations__
, и все. Аннотации являются необязательными и вообще не влияют на выполнение функций Python.
Цитируя Амала из Амаль и ночные посетители : «Какой в таком случае смысл иметь это?»
Во-первых, аннотации — это хорошая документация .Вы, конечно, можете указать ту же информацию в строке документации, но размещение ее непосредственно в определении функции добавляет ясности. Типы аргументов и возвращаемое значение очевидны с первого взгляда для такого заголовка функции:
def f (a: int, b: str) -> float:
Конечно, интерпретатор не требует соблюдения указанных типов, но, по крайней мере, они понятны для тех, кто читает определение функции.
Deep Dive: принудительная проверка типов
Если бы вы были склонны, вы могли бы добавить код для принудительного применения типов, указанных в аннотациях к функциям.Вот функция, которая проверяет фактический тип каждого аргумента на соответствие тому, что указано в аннотации для соответствующего параметра. Он отображает
True
, если они соответствуютFalse
, если нет:>>>
>>> def f (a: int, b: str, c: float): ... импорт проверить ... args = inspect.getfullargspec (f) .args ... аннотации = inspect.getfullargspec (f) .annotations ... для x в аргументах: ... print (x, '->', ... 'arg is', type (locals () [x]), ',', ... 'annotation is', annotations [x], ... '/', (type (locals () [x])) is annotations [x]) ... >>> f (1, 'foo', 3.3) a -> arg - это
, аннотация - это / True b -> arg - , аннотация - / True c -> arg - , аннотация - / True >>> f ('фу', 4.3, 9) a -> arg - это , аннотация - / False b -> arg - , аннотация - / False c -> arg - , аннотация - / False >>> f (1, 'фу', 'бар') a -> arg - это , аннотация - это / True b -> arg - , аннотация - / True c -> arg - , аннотация - / False (Модуль
inspect
содержит функции, которые получают полезную информацию о живых объектах — в данном случае функцияf ()
.)Функция, определенная как указанная выше, при желании может предпринять какие-то корректирующие действия, когда обнаружит, что переданные аргументы не соответствуют типам, указанным в аннотациях.
Фактически, схема использования аннотаций для выполнения проверки статического типа в Python описана в PEP 484. Доступна бесплатная программа проверки статического типа для Python под названием mypy, основанная на спецификации PEP 484.
Есть еще одно преимущество использования аннотаций.Стандартизованный формат, в котором информация аннотаций хранится в атрибуте __annotations__
, позволяет анализировать сигнатуры функций автоматическими инструментами.
В аннотациях нет ничего особенного. Вы даже можете определить свой собственный без специального синтаксиса, предоставляемого Python. Вот определение функции Python с аннотациями объекта типа, прикрепленными к параметрам и возвращаемому значению:
>>>
>>> def f (a: int, b: str) -> float:
... возвращаться
...
>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
По сути, это та же функция со словарем __annotations__
, созданным вручную:
>>>
>>> def f (a, b):
... возвращаться
...
>>> f .__ annotations__ = {'a': int, 'b': str, 'return': float}
>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
Эффект идентичен в обоих случаях, но первый на первый взгляд визуально более привлекателен и удобочитаем.
Фактически, атрибут __annotations__
существенно не отличается от большинства других атрибутов функции. Например, его можно динамически изменять. Вы можете использовать атрибут возвращаемого значения, чтобы подсчитать, сколько раз функция выполняется:
>>>
>>> def f () -> 0:
... f .__ аннотации __ ['return'] + = 1
... print (f "f () был выполнен {f .__ annotations __ ['return']} время (с)")
...
>>> f ()
f () было выполнено 1 раз (а)
>>> f ()
f () было выполнено 2 раза (а)
>>> f ()
f () было выполнено 3 раза (а)
Аннотации функций Python — это не что иное, как словари метаданных.Просто так получилось, что вы можете создать их с помощью удобного синтаксиса, поддерживаемого интерпретатором. Это все, что вы хотите из них сделать.
Заключение
По мере роста приложений становится все более важным модулировать код, разбивая его на более мелкие функции управляемого размера. Надеюсь, теперь у вас есть все необходимые инструменты для этого.
Вы узнали:
- Как создать пользовательскую функцию в Python
- Несколько разных способов передать аргумент функции
- Как вы можете вернуть данные из функции ее вызывающему
- Как добавить документацию к функциям с строками документации и аннотациями
Следующими в этой серии являются два руководства, которые охватывают поиск и сопоставление с образцом .Вы получите подробный обзор модуля Python под названием re , который содержит функции для поиска и сопоставления с использованием универсального синтаксиса шаблонов, называемого регулярным выражением .
На этой странице: def, return, docstrings, help (), функции возврата значения и void Функции: основыДавайте откажемся от старой алгебры. Вы выучили «функции» примерно так:
Попробуем другую функцию.Ниже приведена функция, которая принимает глагол (надеюсь) и возвращает герундийную форму:
Несколько параметров, строка документацииНиже представлена чуть более сложная функция. Он принимает два аргумента, имеет условное выражение в теле функции и начинается со строки:
Строка «» «Проверяет, если …» «» называется « docstring «. Размещенный в самом верху тела функции, он действует как документация по функции. Эта строка распечатывается, когда вы вызываете help () для функции:
Вот еще один пример. Эта функция возвращает список символов, общих для двух строк. (Было бы лучше, если бы не было дубликатов. Можно улучшить?)
Функции: возврат или аннулированиеВы можете подумать: «Подождите, я не видел никакого оператора возврата в учебнике по определению функций». Вы правы — определенная Эд функция get_legal () не включала никакого оператора возврата, а только набор функций печати.В Python можно составить функцию без оператора возврата. Такие функции называются void , и они возвращают None, специальный объект Python «ничего». Вот пример функции void:
Хорошо, тогда чем отличаются функции void и функции типа «return»? Хороший вопрос.Позвольте мне проиллюстрировать это на примерах. Вот функция get_ing (), определенная выше, и ее недействительный аналог print_ing ():
Вызывая две функции, вы сначала замечаете небольшую разницу в выводе. Возвращающая функция дает вам строку (примечание »), а функция печати показывает напечатанный вывод строки — обратите внимание на отсутствие кавычек.Обратите внимание, что возвращаемое значение отображается только в интерактивной среде оболочки; в сценарии только команды печати приводят к отображению вывода.
Теперь, поскольку get_ing () возвращает значение, его можно скопировать в переменную с помощью оператора присваивания. Попробуйте сделать то же самое с print_ing (), и вы столкнетесь с непредвиденными последствиями: печать происходит после оператора присваивания, и в итоге вы не получаете ничего в качестве значения переменной, потому что эта функция, будучи недействительной, ничего не возвращает.
Кроме того, функцию, возвращающую значение, можно подключить прямо к другой функции. Опять же, поскольку функции void ничего не возвращают, они не могут. Ниже get_ing (‘eat’) передается функции len () для успешного результата. С помощью len (print_ing (‘eat’)) печать происходит независимо, а затем возникает ошибка типа:
Наконец, если вам нужна печать, ее также можно выполнить с помощью функции, возвращающей значение: просто используйте с ней оператор печати.
Это заняло некоторое время, но я надеюсь, что теперь вы ясно видите фундаментальные различия между двумя типами функций. По правде говоря, функции возвращаемого типа гораздо более функциональны и полезны. В других языках функции типа void даже не называются функциями — вместо этого они называются процедурами. |
Учебное пособие по Python: функции
Предыдущая глава: Мелкое и глубокое копирование
Следующая глава: Рекурсия и рекурсивные функции
Функции
Синтаксис
Функции — это конструкция для структурирования программ. Они известны в большинстве программ.
языки, иногда также называемые подпрограммами или процедурами. Функции
используются для использования кода более чем в одном месте программы. Единственный способ без
Функция повторного использования кода заключается в копировании кода.
Функция в Python определяется оператором def. Общий синтаксис выглядит как
это:
def имя-функции (список параметров): операторы, то есть тело функции
Список параметров состоит из одного или нескольких параметров. Параметры называются
аргументы, если функция вызывается. Тело функции состоит из
заявления. Тело функции выполняется каждый раз при вызове функции.
Параметр может быть обязательным или необязательным. Необязательные параметры (ноль или более) должны
соблюдать обязательные параметры.
Тела функций могут содержать оператор возврата. Это может быть где угодно в функции
тело. Этот оператор завершает выполнение вызова функции и «возвращает» результат,
то есть значение выражения, следующего за ключевым словом return, для вызывающей стороны.
Если в коде функции нет оператора возврата, функция завершается, когда
поток управления достигает конца тела функции.
Пример:
>>> def add (x, y): ... "" "Вернуть x плюс y" "" ... вернуть x + y ... >>>
В следующем интерактивном сеансе функция, которую мы ранее определили
будет называться:
>>> добавить (4,5) 9 >>> добавить (8,3) 11 >>>
Пример функции с дополнительными параметрами
>>> def add (x, y = 5): ... "" "Вернуть x плюс y, необязательно" "" ... вернуть x + y ... >>>
Вызов этой функции может выглядеть так:
>>> добавить (4) 9 >>> добавить (8,3) 11 >>>
Строка документации
Первый оператор в теле функции обычно представляет собой строку,
к которому можно получить доступ с помощью function_name.__doc__
Этот оператор называется Строка документа .
Пример:
>>> execfile ("function1.py") >>> добавить .__ doc__ 'Возвращает x плюс y' >>> add2 .__ doc__ 'Возвращает x плюс y, необязательно' >>>
Параметры ключевого слова
Использование параметров ключевого слова — это альтернативный способ выполнения вызовов функций.
Определение функции не меняется.
Пример:
def sumsub (a, b, c = 0, d = 0): вернуть a - b + c - d
Ключевыми параметрами могут быть только те, которые не используются в качестве позиционных аргументов.
>>> execfile ("funktion1.py") >>> sumsub (12,4) 8 >>> sumsub (12,4,27,23) 12 >>> sumsub (12,4, d = 27, c = 23) 4
Произвольное количество параметров
В программировании существует множество ситуаций, в которых точное количество необходимых
параметры не могут быть определены априори. Произвольный номер параметра может быть
выполняется на Python с помощью так называемых ссылок на кортежи. Звездочка «*» используется перед
последнего имени параметра, чтобы обозначить его как ссылку на кортеж.Эту звездочку не следует путать с синтаксисом C, где эта нотация связана
с указателями.
Пример:
def произвольно (x, y, * подробнее): напечатать "x =", x, ", y =", y напечатать «произвольно:», подробнее
x и y — обычные позиционные параметры в предыдущей функции.