controlflow.md
1> **Источник:** https://python-all.ru/3.15/tutorial/controlflow.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 4. Дополнительные средства управления потоком89Помимо только что представленного оператора [`while`](https://python-all.ru/3.15/reference/compound_stmts.html#while), Python использует ещё несколько, с которыми мы познакомимся в этой главе.1011## 4.1. `if`Инструкции1213Пожалуй, наиболее известным типом оператора является оператор [`if`](https://python-all.ru/3.15/reference/compound_stmts.html#if). Например:1415```python16>>> x = int(input("Please enter an integer: "))17Please enter an integer: 4218>>> if x < 0:19... x = 020... print('Negative changed to zero')21... elif x == 0:22... print('Zero')23... elif x == 1:24... print('Single')25... else:26... print('More')27...28More29```3031Может быть ноль или более частей [`elif`](https://python-all.ru/3.15/reference/compound_stmts.html#elif), а часть [`else`](https://python-all.ru/3.15/reference/compound_stmts.html#else) является необязательной. Ключевое слово ‘`elif`’ является сокращением от ‘else if’ и полезно для избежания чрезмерного отступа. Последовательность `if` … `elif` … `elif` … является заменой операторов `switch` или `case`, встречающихся в других языках.3233Если вы сравниваете одно и то же значение с несколькими константами или проверяете определённые типы или атрибуты, вам также может пригодиться оператор `match`. Дополнительные сведения см. в [Операторы match](https://python-all.ru/3.15/tutorial/controlflow.html#tut-match).3435## 4.2. `for`Инструкции3637Оператор [`for`](https://python-all.ru/3.15/reference/compound_stmts.html#for) в Python немного отличается от того, к чему вы могли привыкнуть в C или Pascal. Вместо того чтобы всегда выполнять итерацию по арифметической прогрессии чисел (как в Pascal) или давать пользователю возможность задавать как шаг итерации, так и условие остановки (как в C), оператор `for` в Python выполняет итерацию по элементам любой последовательности (списка или строки) в том порядке, в котором они встречаются в последовательности. Например (без каламбура):3839```python40>>> # Измеряем некоторые строки:41>>> words = ['cat', 'window', 'defenestrate']42>>> for w in words:43... print(w, len(w))44...45cat 346window 647defenestrate 1248```4950Код, изменяющий коллекцию во время итерации по той же коллекции, может быть сложным для правильной реализации. Вместо этого обычно проще выполнить цикл по копии коллекции или создать новую коллекцию:5152```python53# Создаём образец коллекции54users = {'Hans': 'active', 'Éléonore': 'inactive', '景太郎': 'active'}5556# Стратегия: перебираем копию57for user, status in users.copy().items():58 if status == 'inactive':59 del users[user]6061# Стратегия: создать новую коллекцию62active_users = {}63for user, status in users.items():64 if status == 'active':65 active_users[user] = status66```6768## 4.3. Функция [`range()`](https://python-all.ru/3.15/library/stdtypes.html#range)6970Если вам действительно нужно выполнить итерацию по последовательности чисел, встроенная функция [`range()`](https://python-all.ru/3.15/library/stdtypes.html#range) оказывается полезной. Она генерирует арифметические прогрессии:7172```python73>>> for i in range(5):74... print(i)75...76077178279380481```8283Указанная конечная точка никогда не входит в сгенерированную последовательность; `range(10)` генерирует 10 значений – допустимые индексы для элементов последовательности длины 10. Можно заставить диапазон начинаться с другого числа или указать другой шаг (даже отрицательный; иногда это называется «шаг»):8485```python86>>> list(range(5, 10))87[5, 6, 7, 8, 9]8889>>> list(range(0, 10, 3))90[0, 3, 6, 9]9192>>> list(range(-10, -100, -30))93[-10, -40, -70]94```9596Для итерации по индексам последовательности можно комбинировать [`range()`](https://python-all.ru/3.15/library/stdtypes.html#range) и [`len()`](https://python-all.ru/3.15/library/functions.html#len) следующим образом:9798```python99>>> a = ['Mary', 'had', 'a', 'little', 'lamb']100>>> for i in range(len(a)):101... print(i, a[i])102...1030 Mary1041 had1052 a1063 little1074 lamb108```109110Однако в большинстве таких случаев удобно использовать функцию [`enumerate()`](https://python-all.ru/3.15/library/functions.html#enumerate), см. [Техники циклической обработки](https://python-all.ru/3.15/tutorial/datastructures.html#tut-loopidioms).111112Странная вещь происходит, если просто вывести range:113114```python115>>> range(10)116range(0, 10)117```118119Во многих отношениях объект, возвращаемый [`range()`](https://python-all.ru/3.15/library/stdtypes.html#range), ведёт себя как список, но на самом деле это не так. Это объект, который при итерации возвращает последовательные элементы нужной последовательности, но на самом деле не создаёт список, экономя тем самым память.120121Такой объект называется [итерируемым](https://python-all.ru/3.15/glossary.html#term-iterable), то есть пригодным в качестве цели для функций и конструкций, которые ожидают нечто, откуда они могут получать последовательные элементы, пока запас не исчерпается. Мы видели, что оператор [`for`](https://python-all.ru/3.15/reference/compound_stmts.html#for) является такой конструкцией, а примером функции, принимающей итерируемый объект, является [`sum()`](https://python-all.ru/3.15/library/functions.html#sum):122123```python124>>> sum(range(4)) # 0 + 1 + 2 + 31256126```127128Позже мы увидим больше функций, которые возвращают итерируемые объекты и принимают их в качестве аргументов. В главе [Структуры данных](https://python-all.ru/3.15/tutorial/datastructures.html#tut-structures) мы более подробно обсудим [`list()`](https://python-all.ru/3.15/library/stdtypes.html#list).129130## 4.4. `break` и `continue` операторы131132Оператор [`break`](https://python-all.ru/3.15/reference/simple_stmts.html#break) прерывает самый внутренний охватывающий цикл [`for`](https://python-all.ru/3.15/reference/compound_stmts.html#for) или [`while`](https://python-all.ru/3.15/reference/compound_stmts.html#while):133134```python135>>> for n in range(2, 10):136... for x in range(2, n):137... if n % x == 0:138... print(f"{n} equals {x} * {n//x}")139... break140...1414 equals 2 * 21426 equals 2 * 31438 equals 2 * 41449 equals 3 * 3145```146147Оператор [`continue`](https://python-all.ru/3.15/reference/simple_stmts.html#continue) переходит к следующей итерации цикла:148149```python150>>> for num in range(2, 10):151... if num % 2 == 0:152... print(f"Found an even number {num}")153... continue154... print(f"Found an odd number {num}")155...156Found an even number 2157Found an odd number 3158Found an even number 4159Found an odd number 5160Found an even number 6161Found an odd number 7162Found an even number 8163Found an odd number 9164```165166## 4.5. `else` Предложения else в циклах167168В цикле `for` или `while` оператор `break` может быть сопряжён с предложением `else`. Если цикл завершается без выполнения `break`, то выполняется предложение `else`.169170В цикле [`for`](https://python-all.ru/3.15/reference/compound_stmts.html#for) предложение `else` выполняется после завершения последней итерации цикла, то есть если не произошло прерывания.171172В цикле [`while`](https://python-all.ru/3.15/reference/compound_stmts.html#while) оно выполняется после того, как условие цикла становится ложным.173174В любом типе цикла предложение `else` **не** выполняется, если цикл был прерван оператором [`break`](https://python-all.ru/3.15/reference/simple_stmts.html#break). Разумеется, другие способы досрочного завершения цикла, такие как [`return`](https://python-all.ru/3.15/reference/simple_stmts.html#return) или возбуждение исключения, также пропускают выполнение предложения [`else`](https://python-all.ru/3.15/reference/compound_stmts.html#else).175176Это демонстрируется в следующем цикле `for`, который ищет простые числа:177178```python179>>> for n in range(2, 10):180... for x in range(2, n):181... if n % x == 0:182... print(n, 'equals', x, '*', n//x)183... break184... else:185... # цикл завершился без нахождения множителя186... print(n, 'is a prime number')187...1882 is a prime number1893 is a prime number1904 equals 2 * 21915 is a prime number1926 equals 2 * 31937 is a prime number1948 equals 2 * 41959 equals 3 * 3196```197198(Да, это правильный код. Присмотритесь: предложение `else` относится к циклу `for`, **а не** к инструкции `if`.)199200Один из способов понять предложение else – представить его в паре с `if` внутри цикла. При выполнении цикла будет выполняться последовательность if/if/if/else. `if` находится внутри цикла и встречается несколько раз. Если условие когда-либо оказывается истинным, происходит `break`. Если условие никогда не истинно, выполняется предложение `else` вне цикла.201202При использовании с циклом предложение `else` имеет больше общего с предложением `else` инструкции [`try`](https://python-all.ru/3.15/reference/compound_stmts.html#try), чем с аналогичным предложением инструкций `if`: предложение `else` инструкции `try` выполняется, когда не возникает исключения, а предложение `else` цикла выполняется, когда не происходит `break`. Подробнее об инструкции `try` и исключениях см. [Обработка исключений](https://python-all.ru/3.15/tutorial/errors.html#tut-handling).203204## 4.6. `pass`Инструкции205206Инструкция [`pass`](https://python-all.ru/3.15/reference/simple_stmts.html#pass) ничего не делает. Она может использоваться, когда синтаксически требуется инструкция, но программа не должна выполнять никаких действий. Например:207208```python209>>> while True:210... pass # Активное ожидание прерывания с клавиатуры (Ctrl+C)211...212```213214Это часто используется для создания минимальных классов:215216```python217>>> class MyEmptyClass:218... pass219...220```221222Ещё одно место, где можно использовать [`pass`](https://python-all.ru/3.15/reference/simple_stmts.html#pass) – в качестве заполнителя для тела функции или условного оператора при работе над новым кодом, позволяя сохранять более абстрактный уровень мышления. `pass` молча игнорируется:223224```python225>>> def initlog(*args):226... pass # Не забудьте реализовать это!227...228```229230В этом последнем случае многие используют литерал многоточия `...` вместо `pass`. Такое использование не имеет особого значения для Python и не является частью определения языка (здесь можно использовать любое константное выражение), но `...` также традиционно используется в качестве тела-заполнителя. См. [Объект Ellipsis](https://python-all.ru/3.15/library/stdtypes.html#bltin-ellipsis-object).231232## 4.7. `match`Инструкции233234Инструкция [`match`](https://python-all.ru/3.15/reference/compound_stmts.html#match) принимает выражение и сравнивает его значение с последовательными шаблонами, заданными в одном или нескольких блоках case. Внешне это напоминает инструкцию switch в C, Java или JavaScript (и многих других языках), но больше похоже на сопоставление с образцом в языках вроде Rust или Haskell. Выполняется только первый подошедший шаблон, и он также может извлекать компоненты (элементы последовательностей или атрибуты объектов) из значения в переменные. Если ни один case не подошёл, ни одна из ветвей не выполняется.235236Простейшая форма сравнивает проверяемое значение с одним или несколькими литералами:237238```python239def http_error(status):240 match status:241 case 400:242 return "Bad request"243 case 404:244 return "Not found"245 case 418:246 return "I'm a teapot"247 case _:248 return "Something's wrong with the internet"249```250251Обратите внимание на последний блок: «имя переменной» `_` действует как *подстановочный знак* и всегда совпадает.252253Можно объединить несколько литералов в одном шаблоне с помощью `|` («или»):254255```python256case 401 | 403 | 404:257 return "Not allowed"258```259260Шаблоны могут выглядеть как распаковывающие присваивания и могут использоваться для связывания переменных:261262```python263# point – это кортеж (x, y)264match point:265 case (0, 0):266 print("Origin")267 case (0, y):268 print(f"Y={y}")269 case (x, 0):270 print(f"X={x}")271 case (x, y):272 print(f"X={x}, Y={y}")273 case _:274 raise ValueError("Not a point")275```276277Изучите этот пример внимательно! Первый шаблон содержит два литерала и может рассматриваться как расширение литерального шаблона, показанного выше. Но следующие два шаблона объединяют литерал и переменную, и переменная *связывает* значение из проверяемого объекта (`point`). Четвёртый шаблон захватывает два значения, что концептуально похоже на распаковывающее присваивание `(x, y) = point`.278279Если вы используете классы для структурирования данных, можно использовать имя класса, за которым следует список аргументов, напоминающий конструктор, но с возможностью захвата атрибутов в переменные:280281```python282class Point:283 def __init__(self, x, y):284 self.x = x285 self.y = y286287def where_is(point):288 match point:289 case Point(x=0, y=0):290 print("Origin")291 case Point(x=0, y=y):292 print(f"Y={y}")293 case Point(x=x, y=0):294 print(f"X={x}")295 case Point():296 print("Somewhere else")297 case _:298 print("Not a point")299```300301Можно использовать позиционные параметры с некоторыми встроенными классами, которые предоставляют упорядочение для своих атрибутов (например, dataclasses). Также можно определить конкретную позицию для атрибутов в шаблонах, установив специальный атрибут `__match_args__` в своих классах. Если он установлен в (“x”, “y”), следующие шаблоны эквивалентны (и все связывают атрибут `y` с переменной `var`):302303```python304Point(1, var)305Point(1, y=var)306Point(x=1, y=var)307Point(y=var, x=1)308```309310Рекомендуемый способ чтения шаблонов – рассматривать их как расширенную форму того, что можно было бы поставить слева от присваивания, чтобы понять, какие переменные будут чему присвоены. Только отдельные имена (например, `var` выше) присваиваются инструкцией match. Составные имена (например, `foo.bar`), имена атрибутов (`x=` и `y=` выше) или имена классов (распознаваемые по “(…)” рядом с ними, как `Point` выше) никогда не присваиваются.311312Шаблоны могут быть произвольно вложенными. Например, если у нас есть короткий список точек с добавленным `__match_args__`, можно сопоставить его так:313314```python315class Point:316 __match_args__ = ('x', 'y')317 def __init__(self, x, y):318 self.x = x319 self.y = y320321match points:322 case []:323 print("No points")324 case [Point(0, 0)]:325 print("The origin")326 case [Point(x, y)]:327 print(f"Single point {x}, {y}")328 case [Point(0, y1), Point(0, y2)]:329 print(f"Two on the Y axis at {y1}, {y2}")330 case _:331 print("Something else")332```333334К шаблону можно добавить предложение `if`, известное как «страж». Если страж ложен, `match` переходит к следующему блоку case. Обратите внимание, что захват значения происходит до вычисления стража:335336```python337match point:338 case Point(x, y) if x == y:339 print(f"Y=X at {x}")340 case Point(x, y):341 print(f"Not on the diagonal")342```343344Несколько других ключевых особенностей этой инструкции:345346- Как и при распаковывающих присваиваниях, шаблоны кортежей и списков имеют в точности одинаковое значение и фактически сопоставляются с произвольными последовательностями. Важное исключение: они не сопоставляются с итераторами или строками.347- Шаблоны последовательностей поддерживают расширенную распаковку: `[x, y, *rest]` и `(x, y, *rest)` работают аналогично распаковывающим присваиваниям. Имя после `*` может быть также `_`, поэтому `(x, y, *_)` сопоставляется с последовательностью из как минимум двух элементов, не связывая остальные.348- Шаблоны отображений: `{"bandwidth": b, "latency": l}` захватывает значения `"bandwidth"` и `"latency"` из словаря. В отличие от шаблонов последовательностей, лишние ключи игнорируются. Также поддерживается распаковка вида `**rest`. (Но `**_` было бы избыточным, поэтому не допускается.)349- Подшаблоны могут быть захвачены с помощью ключевого слова `as`:350351 ```python352 case (Point(x1, y1), Point(x2, y2) as p2): ...353 ```354355 захватит второй элемент входных данных как `p2` (при условии, что входные данные – последовательность из двух точек)356- Большинство литералов сравниваются по равенству, однако синглтоны `True`, `False` и `None` сравниваются по идентичности.357- Шаблоны могут использовать именованные константы. Они должны быть составными именами (с точкой), чтобы не интерпретироваться как переменные захвата:358359 ```python360 from enum import Enum361 class Color(Enum):362 RED = 'red'363 GREEN = 'green'364 BLUE = 'blue'365366 color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))367368 match color:369 case Color.RED:370 print("I see red!")371 case Color.GREEN:372 print("Grass is green")373 case Color.BLUE:374 print("I'm feeling the blues :(")375 ```376377Более подробное объяснение и дополнительные примеры можно найти в [**PEP 636**](https://python-all.ru/3.15/tutorial/controlflow.html), который написан в формате учебного пособия.378379## 4.8. Определение функций380381Можно создать функцию, которая выводит ряд Фибоначчи до произвольной границы:382383```python384>>> def fib(n): # вывести ряд Фибоначчи, меньший n385... """Вывести ряд Фибоначчи, меньший n."""386... a, b = 0, 1387... while a < n:388... print(a, end=' ')389... a, b = b, a+b390... print()391...392>>> # Теперь вызовите только что определённую функцию:393>>> fib(2000)3940 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597395```396397Ключевое слово [`def`](https://python-all.ru/3.15/reference/compound_stmts.html#def) вводит *определение* функции. За ним должны следовать имя функции и список формальных параметров в скобках. Инструкции, составляющие тело функции, начинаются со следующей строки и должны иметь отступ.398399Первый оператор тела функции может быть строковым литералом; этот строковый литерал является строкой документации функции, или *docstring*. (Подробнее о docstring можно найти в разделе [Строки документации](https://python-all.ru/3.15/tutorial/controlflow.html#tut-docstrings).) Существуют инструменты, которые используют docstring для автоматического создания онлайн- или печатной документации, или чтобы позволить пользователю интерактивно просматривать код; рекомендуется включать docstring в код, который вы пишете, так что сделайте это привычкой.400401*Выполнение* функции вводит новую таблицу символов, используемую для локальных переменных функции. Точнее, все присваивания переменных в функции сохраняют значение в локальной таблице символов; тогда как обращения к переменным сначала ищут в локальной таблице символов, затем в локальных таблицах символов объемлющих функций, затем в глобальной таблице символов и, наконец, в таблице встроенных имён. Таким образом, глобальные переменные и переменные объемлющих функций не могут быть напрямую присвоены внутри функции (если только, для глобальных переменных, они не указаны в операторе [`global`](https://python-all.ru/3.15/reference/simple_stmts.html#global), или, для переменных объемлющих функций, в операторе [`nonlocal`](https://python-all.ru/3.15/reference/simple_stmts.html#nonlocal)), хотя на них можно ссылаться.402403The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using *call by value* (where the *value* is always an object *reference*, not the value of the object). [\[1\]](https://python-all.ru/3.15/tutorial/controlflow.html#id2) When a function calls another function, or calls itself recursively, a new local symbol table is created for that call.404405Определение функции связывает имя функции с объектом функции в текущей таблице символов. Интерпретатор распознаёт объект, на который указывает это имя, как определённую пользователем функцию. Другие имена также могут указывать на тот же объект функции и использоваться для доступа к функции:406407```python408>>> fib409<function fib at 10042ed0>410>>> f = fib411>>> f(100)4120 1 1 2 3 5 8 13 21 34 55 89413```414415Приходя из других языков, вы можете возразить, что `fib` – это не функция, а процедура, поскольку она не возвращает значение. На самом деле даже функции без оператора [`return`](https://python-all.ru/3.15/reference/simple_stmts.html#return) возвращают значение, хотя и довольно скучное. Это значение называется `None` (это встроенное имя). Запись значения `None` обычно подавляется интерпретатором, если оно было бы единственным записанным значением. Вы можете увидеть его, если действительно захотите, с помощью [`print()`](https://python-all.ru/3.15/library/functions.html#print):416417```python418>>> fib(0)419>>> print(fib(0))420None421```422423Просто написать функцию, которая возвращает список чисел ряда Фибоначчи, вместо того чтобы выводить его:424425```python426>>> def fib2(n): # возвращает ряд Фибоначчи до n427... """Возвращает список, содержащий ряд Фибоначчи до n."""428... result = []429... a, b = 0, 1430... while a < n:431... result.append(a) # см. ниже432... a, b = b, a+b433... return result434...435>>> f100 = fib2(100) # вызов436>>> f100 # вывод результата437[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]438```439440Этот пример, как обычно, демонстрирует некоторые новые возможности Python:441442- Оператор [`return`](https://python-all.ru/3.15/reference/simple_stmts.html#return) возвращает значение из функции. `return` без выражения-аргумента возвращает `None`. Завершение функции без явного возврата также возвращает `None`.443- Оператор `result.append(a)` вызывает *метод* объекта списка `result`. Метод – это функция, которая «принадлежит» объекту и имеет имя `obj.methodname`, где `obj` – некоторый объект (это может быть выражение), а `methodname` – имя метода, определённого типом объекта. Разные типы определяют разные методы. Методы разных типов могут иметь одинаковые имена без неоднозначности. (Можно определять собственные типы объектов и методы, используя *классы*; см. [Классы](https://python-all.ru/3.15/tutorial/classes.html#tut-classes)). Метод [`append()`](https://python-all.ru/3.15/library/stdtypes.html#list.append), показанный в примере, определён для объектов списка; он добавляет новый элемент в конец списка. В этом примере он эквивалентен `result = result + [a]`, но более эффективен.444445## 4.9. Подробнее об определении функций446447Также можно определять функции с переменным числом аргументов. Существует три формы, которые можно комбинировать.448449### 4.9.1. Значения аргументов по умолчанию450451Наиболее полезная форма – указать значение по умолчанию для одного или нескольких аргументов. Это создаёт функцию, которую можно вызывать с меньшим количеством аргументов, чем она определена допускать. Например:452453```python454def ask_ok(prompt, retries=4, reminder='Please try again!'):455 while True:456 reply = input(prompt)457 if reply in {'y', 'ye', 'yes'}:458 return True459 if reply in {'n', 'no', 'nop', 'nope'}:460 return False461 retries = retries - 1462 if retries < 0:463 raise ValueError('invalid user response')464 print(reminder)465```466467Эту функцию можно вызывать несколькими способами:468469- передавая только обязательный аргумент: `ask_ok('Do you really want to quit?')`470- передавая один из необязательных аргументов: `ask_ok('OK to overwrite the file?', 2)`471- или даже передавая все аргументы: `ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')`472473Этот пример также вводит ключевое слово [`in`](https://python-all.ru/3.15/reference/expressions.html#in). Оно проверяет, содержит ли последовательность определённое значение.474475Значения по умолчанию вычисляются в точке определения функции в *определяющей* области видимости, так что476477```python478i = 5479480def f(arg=i):481 print(arg)482483i = 6484f()485```486487выведет `5`.488489**Важное предупреждение:** Значение по умолчанию вычисляется только один раз. Это имеет значение, когда значение по умолчанию является изменяемым объектом, таким как список, словарь или экземпляры большинства классов. Например, следующая функция накапливает аргументы, переданные ей при последующих вызовах:490491```python492def f(a, L=[]):493 L.append(a)494 return L495496print(f(1))497print(f(2))498print(f(3))499```500501Это выведет502503```python504[1]505[1, 2]506[1, 2, 3]507```508509Если вы не хотите, чтобы значение по умолчанию разделялось между последующими вызовами, вы можете написать функцию так:510511```python512def f(a, L=None):513 if L is None:514 L = []515 L.append(a)516 return L517```518519### 4.9.2. Именованные аргументы520521Функции также можно вызывать с помощью [именованных аргументов](https://python-all.ru/3.15/glossary.html#term-keyword-argument) вида `kwarg=value`. Например, следующая функция:522523```python524def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):525 print("-- This parrot wouldn't", action, end=' ')526 print("if you put", voltage, "volts through it.")527 print("-- Lovely plumage, the", type)528 print("-- It's", state, "!")529```530531принимает один обязательный аргумент (`voltage`) и три необязательных аргумента (`state`, `action` и `type`). Эту функцию можно вызывать любым из следующих способов:532533```python534parrot(1000) # 1 позиционный аргумент535parrot(voltage=1000) # 1 именованный аргумент536parrot(voltage=1000000, action='VOOOOOM') # 2 именованных аргумента537parrot(action='VOOOOOM', voltage=1000000) # 2 именованных аргумента538parrot('a million', 'bereft of life', 'jump') # 3 позиционных аргумента539parrot('a thousand', state='pushing up the daisies') # 1 позиционный, 1 именованный540```541542но все следующие вызовы будут недопустимы:543544```python545parrot() # отсутствует обязательный аргумент546parrot(voltage=5.0, 'dead') # неименованный аргумент после именованного547parrot(110, voltage=220) # дублирование значения для одного и того же аргумента548parrot(actor='John Cleese') # неизвестный именованный аргумент549```550551В вызове функции именованные аргументы должны следовать за позиционными. Все переданные именованные аргументы должны соответствовать одному из аргументов, принимаемых функцией (например, `actor` не является допустимым аргументом для функции `parrot`), и их порядок не важен. Это также включает необязательные аргументы (например, `parrot(voltage=1000)` тоже допустим). Ни один аргумент не может получать значение более одного раза. Вот пример, который завершается ошибкой из-за этого ограничения:552553```python554>>> def function(a):555... pass556...557>>> function(0, a=0)558Traceback (most recent call last):559 File "<stdin>", line 1, in <module>560TypeError: function() got multiple values for argument 'a'561```562563Когда присутствует последний формальный параметр вида `**name`, он получает словарь (см. [Типы отображений – dict, frozendict](https://python-all.ru/3.15/library/stdtypes.html#typesmapping)), содержащий все именованные аргументы, кроме тех, которые соответствуют формальному параметру. Это можно комбинировать с формальным параметром вида `*name` (описан в следующем подразделе), который получает [кортеж](https://python-all.ru/3.15/tutorial/datastructures.html#tut-tuples), содержащий позиционные аргументы сверх списка формальных параметров. (`*name` должен находиться перед `**name`.) Например, если определить функцию следующим образом:564565```python566def cheeseshop(kind, *arguments, **keywords):567 print("-- Do you have any", kind, "?")568 print("-- I'm sorry, we're all out of", kind)569 for arg in arguments:570 print(arg)571 print("-" * 40)572 for kw in keywords:573 print(kw, ":", keywords[kw])574```575576Её можно было бы вызвать так:577578```python579cheeseshop("Limburger", "It's very runny, sir.",580 "It's really very, VERY runny, sir.",581 shopkeeper="Michael Palin",582 client="John Cleese",583 sketch="Cheese Shop Sketch")584```585586и, конечно, она выведет:587588```text589-- Do you have any Limburger ?590-- I'm sorry, we're all out of Limburger591It's very runny, sir.592It's really very, VERY runny, sir.593----------------------------------------594shopkeeper : Michael Palin595client : John Cleese596sketch : Cheese Shop Sketch597```598599Обратите внимание, что порядок, в котором выводятся именованные аргументы, гарантированно соответствует порядку, в котором они были указаны в вызове функции.600601### 4.9.3. Специальные параметры602603По умолчанию аргументы функции Python могут передаваться либо по позиции, либо явно по ключевому слову. Для удобочитаемости и производительности имеет смысл ограничить способ передачи аргументов, чтобы разработчику достаточно было взглянуть на определение функции и определить, передаются ли элементы по позиции, по позиции или по ключевому слову, или только по ключевому слову.604605Определение функции может выглядеть так:606607```text608def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):609 ----------- ---------- ----------610 | | |611 | Positional or keyword |612 | - Keyword only613 -- Positional only614```615616где `/` и `*` являются необязательными. Если они используются, эти символы указывают на вид параметра в зависимости от того, как аргументы могут передаваться функции: только по позиции, по позиции или ключевому слову и только по ключевому слову. Параметры, передаваемые по ключевому слову, также называют именованными параметрами.617618#### 4.9.3.1. Аргументы, передаваемые по позиции или по ключевому слову619620Если `/` и `*` отсутствуют в определении функции, аргументы могут передаваться функции по позиции или по ключевому слову.621622#### 4.9.3.2. Параметры только по позиции623624Рассмотрим это подробнее: можно пометить некоторые параметры как *только по позиции*. Если параметры *только по позиции*, их порядок имеет значение, и их нельзя передавать по ключевому слову. Параметры только по позиции помещаются перед `/` (прямая косая черта). Символ `/` используется для логического отделения параметров только по позиции от остальных. Если в определении функции нет `/`, то параметров только по позиции нет.625626Параметры, следующие после `/`, могут быть *позиционными или ключевыми* или *только по ключевому слову*.627628#### 4.9.3.3. Аргументы только по ключевому слову629630Чтобы пометить параметры как *только по ключевому слову* (то есть они должны передаваться только как именованные аргументы), поместите `*` в списке аргументов непосредственно перед первым *только по ключевому слову* параметром.631632#### 4.9.3.4. Примеры функций633634Рассмотрим следующие примеры определений функций, обращая особое внимание на маркеры `/` и `*`:635636```python637>>> def standard_arg(arg):638... print(arg)639...640>>> def pos_only_arg(arg, /):641... print(arg)642...643>>> def kwd_only_arg(*, arg):644... print(arg)645...646>>> def combined_example(pos_only, /, standard, *, kwd_only):647... print(pos_only, standard, kwd_only)648```649650Первое определение функции, `standard_arg`, наиболее привычная форма, не накладывает ограничений на способ вызова, и аргументы могут передаваться по позиции или по ключевому слову:651652```python653>>> standard_arg(2)6542655656>>> standard_arg(arg=2)6572658```659660Вторая функция `pos_only_arg` ограничена использованием только позиционных параметров, так как в определении функции присутствует `/`:661662```python663>>> pos_only_arg(1)6641665666>>> pos_only_arg(arg=1)667Traceback (most recent call last):668 File "<stdin>", line 1, in <module>669TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'670```671672Третья функция `kwd_only_arg` допускает только именованные аргументы, на что указывает `*` в определении функции:673674```python675>>> kwd_only_arg(3)676Traceback (most recent call last):677 File "<stdin>", line 1, in <module>678TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given679680>>> kwd_only_arg(arg=3)6813682```683684И последняя использует все три способа вызова в одном определении функции:685686```python687>>> combined_example(1, 2, 3)688Traceback (most recent call last):689 File "<stdin>", line 1, in <module>690TypeError: combined_example() takes 2 positional arguments but 3 were given691692>>> combined_example(1, 2, kwd_only=3)6931 2 3694695>>> combined_example(1, standard=2, kwd_only=3)6961 2 3697698>>> combined_example(pos_only=1, standard=2, kwd_only=3)699Traceback (most recent call last):700 File "<stdin>", line 1, in <module>701TypeError: combined_example() got some positional-only arguments passed as keyword arguments: 'pos_only'702```703704Наконец, рассмотрим такое определение функции, где возможно пересечение между позиционным аргументом `name` и `**kwds`, у которого `name` является ключом:705706```python707def foo(name, **kwds):708 return 'name' in kwds709```710711Не существует вызова, который заставил бы её вернуть `True`, поскольку ключевое слово `'name'` всегда будет привязано к первому параметру. Например:712713```python714>>> foo(1, **{'name': 2})715Traceback (most recent call last):716 File "<stdin>", line 1, in <module>717TypeError: foo() got multiple values for argument 'name'718>>>719```720721Но при использовании `/` (аргументы только по позиции) это возможно, поскольку он позволяет передать `name` как позиционный аргумент, а `'name'` как ключ в именованных аргументах:722723```python724>>> def foo(name, /, **kwds):725... return 'name' in kwds726...727>>> foo(1, **{'name': 2})728True729```730731Иными словами, имена позиционных параметров (только по позиции) можно использовать в `**kwds` без неоднозначности.732733#### 4.9.3.5. Итог734735Сценарий использования определяет, какие параметры использовать в определении функции:736737```python738def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):739```740741В качестве рекомендации:742743- Используйте параметры только по позиции, если вы не хотите, чтобы имена параметров были доступны пользователю. Это полезно, когда имена параметров не имеют реального значения, если нужно принудительно задать порядок аргументов при вызове функции или если требуется принимать некоторые позиционные параметры вместе с произвольными ключевыми словами.744- Используйте параметры только по ключевому слову, когда имена имеют значение, и определение функции становится более понятным благодаря явному указанию имён, или если вы хотите предотвратить зависимость пользователей от порядка передаваемых аргументов.745- Для API используйте параметры только по позиции, чтобы избежать разрушительных изменений API, если в будущем имя параметра будет изменено.746747### 4.9.4. Произвольные списки аргументов748749Наконец, наименее часто используемая возможность – указать, что функцию можно вызывать с произвольным количеством аргументов. Эти аргументы будут упакованы в кортеж (см. [Кортежи и последовательности](https://python-all.ru/3.15/tutorial/datastructures.html#tut-tuples)). Перед переменным числом аргументов может быть ноль или более обычных аргументов.750751```python752def write_multiple_items(file, separator, *args):753 file.write(separator.join(args))754```755756Обычно эти *вариативные* аргументы находятся последними в списке формальных параметров, поскольку они собирают все остальные входные аргументы, переданные функции. Любые формальные параметры, которые идут после `*args`, являются аргументами «только по ключевому слову», то есть могут использоваться только как именованные, а не позиционные аргументы.757758```python759>>> def concat(*args, sep="/"):760... return sep.join(args)761...762>>> concat("earth", "mars", "venus")763'earth/mars/venus'764>>> concat("earth", "mars", "venus", sep=".")765'earth.mars.venus'766```767768### 4.9.5. Распаковка списков аргументов769770Обратная ситуация возникает, когда аргументы уже находятся в списке или кортеже, но их нужно распаковать для вызова функции, требующей отдельных позиционных аргументов. Например, встроенная функция [`range()`](https://python-all.ru/3.15/library/stdtypes.html#range) ожидает отдельные аргументы *start* и *stop*. Если они недоступны по отдельности, запишите вызов функции с оператором `*`, чтобы распаковать аргументы из списка или кортежа:771772```python773>>> list(range(3, 6)) # обычный вызов с отдельными аргументами774[3, 4, 5]775>>> args = [3, 6]776>>> list(range(*args)) # вызов с аргументами, распакованными из списка777[3, 4, 5]778```779780Аналогично, словари могут передавать именованные аргументы с помощью оператора `**`:781782```python783>>> def parrot(voltage, state='a stiff', action='voom'):784... print("-- This parrot wouldn't", action, end=' ')785... print("if you put", voltage, "volts through it.", end=' ')786... print("E's", state, "!")787...788>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}789>>> parrot(**d)790-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !791```792793### 4.9.6. Лямбда-выражения794795Небольшие анонимные функции можно создать с помощью ключевого слова [`lambda`](https://python-all.ru/3.15/reference/expressions.html#lambda). Эта функция возвращает сумму двух своих аргументов: `lambda a, b: a+b`. Лямбда-функции можно использовать везде, где требуются объекты функций. Синтаксически они ограничены одним выражением. Семантически это просто синтаксический сахар для обычного определения функции. Как и вложенные определения функций, лямбда-функции могут ссылаться на переменные из содержащей области видимости:796797```python798>>> def make_incrementor(n):799... return lambda x: x + n800...801>>> f = make_incrementor(42)802>>> f(0)80342804>>> f(1)80543806```807808В приведённом выше примере лямбда-выражение используется для возврата функции. Другое применение – передача небольшой функции в качестве аргумента. Например, [`list.sort()`](https://python-all.ru/3.15/library/stdtypes.html#list.sort) принимает функцию ключа сортировки *key*, которой может быть лямбда-функция:809810```python811>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]812>>> pairs.sort(key=lambda pair: pair[1])813>>> pairs814[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]815```816817### 4.9.7. Строки документации818819Вот некоторые соглашения о содержании и форматировании строк документации.820821Первая строка всегда должна быть кратким и сжатым описанием назначения объекта. Для краткости в ней не следует явно указывать имя или тип объекта, так как они доступны другими способами (кроме случая, когда имя оказывается глаголом, описывающим действие функции). Эта строка должна начинаться с заглавной буквы и заканчиваться точкой.822823Если в строке документации есть несколько строк, вторая строка должна быть пустой, чтобы визуально отделить краткое описание от остальной части. Последующие строки должны быть одним или несколькими абзацами, описывающими соглашения о вызове объекта, его побочные эффекты и т.д.824825Парсер Python удаляет отступы из многострочных строковых литералов, когда они используются в качестве строк документации модуля, класса или функции.826827Вот пример многострочной строки документации:828829```python830>>> def my_function():831... """Ничего не делает, но документирует.832...833... Нет, правда, она ничего не делает:834...835... >>> my_function()836... >>>837... """838... pass839...840>>> print(my_function.__doc__)841Do nothing, but document it.842843No, really, it doesn't do anything:844845 >>> my_function()846 >>>847```848849### 4.9.8. Аннотации функций850851[Аннотации функций](https://python-all.ru/3.15/reference/compound_stmts.html#function) – это полностью необязательная метаинформация о типах, используемых пользовательскими функциями (см. [**PEP 3107**](https://python-all.ru/3.15/tutorial/controlflow.html) и [**PEP 484**](https://python-all.ru/3.15/tutorial/controlflow.html) для получения дополнительной информации).852853[Аннотации](https://python-all.ru/3.15/glossary.html#term-function-annotation) хранятся в атрибуте [`__annotations__`](https://python-all.ru/3.15/reference/datamodel.html#object.__annotations__) функции в виде словаря и не влияют ни на какую другую часть функции. Аннотации параметров задаются двоеточием после имени параметра, за которым следует выражение, вычисляющее значение аннотации. Аннотации возвращаемых значений задаются литералом `->`, за которым следует выражение, между списком параметров и двоеточием, обозначающим конец инструкции [`def`](https://python-all.ru/3.15/reference/compound_stmts.html#def). В следующем примере аннотированы обязательный аргумент, необязательный аргумент и возвращаемое значение:854855```python856>>> def f(ham: str, eggs: str = 'eggs') -> str:857... print("Annotations:", f.__annotations__)858... print("Arguments:", ham, eggs)859... return ham + ' and ' + eggs860...861>>> f('spam')862Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}863Arguments: spam eggs864'spam and eggs'865```866867## 4.10. Интермеццо: Стиль кодирования868869Теперь, когда вы собираетесь писать более длинные и сложные фрагменты кода на Python, самое время поговорить о *стиле кодирования*. Большинство языков можно писать (или, точнее, *форматировать*) в разных стилях; одни более читабельны, чем другие. Облегчать другим чтение вашего кода – всегда хорошая идея, и принятие хорошего стиля кодирования в этом очень помогает.870871Для Python [**PEP 8**](https://python-all.ru/3.15/tutorial/controlflow.html) стал руководством по стилю, которому следуют большинство проектов; он продвигает очень читаемый и приятный глазу стиль кодирования. Каждый разработчик Python должен прочитать его в какой-то момент; вот наиболее важные моменты, извлечённые для вас:872873- Используйте отступы в 4 пробела и никаких табуляций.874875 4 пробела – хороший компромисс между маленьким отступом (позволяет большую глубину вложенности) и большим отступом (легче читать). Табуляция вносит путаницу, и её лучше избегать.876- Переносите строки так, чтобы они не превышали 79 символов.877878 Это помогает пользователям с маленькими экранами и позволяет размещать несколько файлов с кодом рядом на больших экранах.879- Используйте пустые строки для разделения функций и классов, а также крупных блоков кода внутри функций.880- По возможности размещайте комментарии на отдельных строках.881- Используйте строки документации.882- Используйте пробелы вокруг операторов и после запятых, но не непосредственно внутри скобочных конструкций: `a = f(1, 2) + g(3, 4)`.883- Давайте классам и функциям согласованные имена; принято использовать `UpperCamelCase` для классов и `lowercase_with_underscores` для функций и методов. Всегда используйте `self` в качестве имени первого аргумента метода (см. [Первый взгляд на классы](https://python-all.ru/3.15/tutorial/classes.html#tut-firstclasses) для получения дополнительной информации о классах и методах).884- Не используйте экзотические кодировки, если ваш код предназначен для использования в международной среде. Стандартная кодировка Python, UTF-8 или даже обычный ASCII в любом случае подходят лучше всего.885- Аналогично, не используйте символы, не входящие в ASCII, в идентификаторах, если есть хоть малейшая вероятность, что код будут читать или сопровождать люди, говорящие на другом языке.886887Сноски888889\[[1](https://python-all.ru/3.15/tutorial/controlflow.html#id1)\]890891На самом деле, *вызов по ссылке на объект* было бы лучшим описанием, поскольку если передаётся изменяемый объект, вызывающий увидит любые изменения, вносимые вызываемым (например, элементы, добавленные в список).892