Документация Python неофициальный перевод

controlflow.md

712 строк · 51.0 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.8/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.8/reference/compound_stmts.html#while), Python использует обычные операторы управления потоком, известные из других языков, с некоторыми особенностями.1011## 4.1. `if`Инструкции1213Пожалуй, наиболее известным типом оператора является оператор [`if`](https://python-all.ru/3.8/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.8/reference/compound_stmts.html#elif), а часть [`else`](https://python-all.ru/3.8/reference/compound_stmts.html#else) является необязательной. Ключевое слово ‘`elif`’ является сокращением от ‘else if’ и полезно для избежания чрезмерного отступа. Последовательность `if``elif``elif` … является заменой операторов `switch` или `case`, встречающихся в других языках.3233## 4.2. `for`Инструкции3435Оператор [`for`](https://python-all.ru/3.8/reference/compound_stmts.html#for) в Python немного отличается от того, к чему вы могли привыкнуть в C или Pascal. Вместо того чтобы всегда выполнять итерацию по арифметической прогрессии чисел (как в Pascal) или давать пользователю возможность задавать как шаг итерации, так и условие остановки (как в C), оператор `for` в Python выполняет итерацию по элементам любой последовательности (списка или строки) в том порядке, в котором они встречаются в последовательности. Например (без каламбура):3637```python38>>> # Измеряем некоторые строки:39... words = ['cat', 'window', 'defenestrate']40>>> for w in words:41...     print(w, len(w))42...43cat 344window 645defenestrate 1246```4748Код, изменяющий коллекцию во время итерации по той же коллекции, может быть сложным для правильной реализации. Вместо этого обычно проще выполнить цикл по копии коллекции или создать новую коллекцию:4950```python51# Стратегия: перебираем копию52for user, status in users.copy().items():53    if status == 'inactive':54        del users[user]5556# Стратегия: создать новую коллекцию57active_users = {}58for user, status in users.items():59    if status == 'active':60        active_users[user] = status61```6263## 4.3. Функция [`range()`](https://python-all.ru/3.8/library/stdtypes.html#range)6465Если вам действительно нужно выполнить итерацию по последовательности чисел, встроенная функция [`range()`](https://python-all.ru/3.8/library/stdtypes.html#range) оказывается полезной. Она генерирует арифметические прогрессии:6667```python68>>> for i in range(5):69...     print(i)70...71072173274375476```7778Указанная конечная точка никогда не входит в сгенерированную последовательность; `range(10)` генерирует 10 значений – допустимые индексы для элементов последовательности длины 10. Можно заставить диапазон начинаться с другого числа или указать другой шаг (даже отрицательный; иногда это называется «шаг»):7980```python81range(5, 10)82   5, 6, 7, 8, 98384range(0, 10, 3)85   0, 3, 6, 98687range(-10, -100, -30)88  -10, -40, -7089```9091Для итерации по индексам последовательности можно комбинировать [`range()`](https://python-all.ru/3.8/library/stdtypes.html#range) и [`len()`](https://python-all.ru/3.8/library/functions.html#len) следующим образом:9293```python94>>> a = ['Mary', 'had', 'a', 'little', 'lamb']95>>> for i in range(len(a)):96...     print(i, a[i])97...980 Mary991 had1002 a1013 little1024 lamb103```104105Однако в большинстве таких случаев удобно использовать функцию [`enumerate()`](https://python-all.ru/3.8/library/functions.html#enumerate), см. [Техники циклической обработки](https://python-all.ru/3.8/tutorial/datastructures.html#tut-loopidioms).106107Странная вещь происходит, если просто вывести range:108109```python110>>> print(range(10))111range(0, 10)112```113114Во многих отношениях объект, возвращаемый [`range()`](https://python-all.ru/3.8/library/stdtypes.html#range), ведёт себя как список, но на самом деле это не так. Это объект, который при итерации возвращает последовательные элементы нужной последовательности, но на самом деле не создаёт список, экономя тем самым память.115116Такой объект называется [итерируемым](https://python-all.ru/3.8/glossary.html#term-iterable), то есть пригодным в качестве цели для функций и конструкций, которые ожидают нечто, откуда они могут получать последовательные элементы, пока запас не исчерпается. Мы видели, что оператор [`for`](https://python-all.ru/3.8/reference/compound_stmts.html#for) является такой конструкцией, а примером функции, принимающей итерируемый объект, является [`sum()`](https://python-all.ru/3.8/library/functions.html#sum):117118```python119>>> sum(range(4))  # 0 + 1 + 2 + 31206121```122123Позже мы увидим больше функций, которые возвращают итерируемые объекты и принимают их в качестве аргументов. И, наконец, возможно, вам интересно, как получить список из range. Вот решение:124125```python126>>> list(range(4))127[0, 1, 2, 3]128```129130В главе [Структуры данных](https://python-all.ru/3.8/tutorial/datastructures.html#tut-structures) мы более подробно обсудим [`list()`](https://python-all.ru/3.8/library/stdtypes.html#list).131132## 4.4. `break` и `continue` операторы, и `else` предложения в циклах133134Оператор [`break`](https://python-all.ru/3.8/reference/simple_stmts.html#break), как и в C, прерывает выполнение самого внутреннего цикла [`for`](https://python-all.ru/3.8/reference/compound_stmts.html#for) или [`while`](https://python-all.ru/3.8/reference/compound_stmts.html#while).135136Операторы цикла могут иметь предложение `else`; оно выполняется, когда цикл завершается из-за исчерпания итератора (с [`for`](https://python-all.ru/3.8/reference/compound_stmts.html#for)) или когда условие становится ложным (с [`while`](https://python-all.ru/3.8/reference/compound_stmts.html#while)), но не когда цикл прерывается оператором [`break`](https://python-all.ru/3.8/reference/simple_stmts.html#break). Это демонстрируется следующим циклом, который ищет простые числа:137138```python139>>> for n in range(2, 10):140...     for x in range(2, n):141...         if n % x == 0:142...             print(n, 'equals', x, '*', n//x)143...             break144...     else:145...         # цикл завершился без нахождения множителя146...         print(n, 'is a prime number')147...1482 is a prime number1493 is a prime number1504 equals 2 * 21515 is a prime number1526 equals 2 * 31537 is a prime number1548 equals 2 * 41559 equals 3 * 3156```157158(Да, это правильный код. Присмотритесь: предложение `else` относится к циклу [`for`](https://python-all.ru/3.8/reference/compound_stmts.html#for), **а не** к инструкции [`if`](https://python-all.ru/3.8/reference/compound_stmts.html#if).)159160При использовании с циклом предложение `else` имеет больше общего с предложением `else` оператора [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try), чем с предложением [`if`](https://python-all.ru/3.8/reference/compound_stmts.html#if) операторов: предложение `else` оператора [`try`](https://python-all.ru/3.8/reference/compound_stmts.html#try) выполняется когда не возникает исключение, а предложение `else` цикла выполняется, когда не возникает `break` . Подробнее об операторе `try` и исключениях см. [Обработка исключений](https://python-all.ru/3.8/tutorial/errors.html#tut-handling).161162Оператор [`continue`](https://python-all.ru/3.8/reference/simple_stmts.html#continue), также заимствованный из C, переходит к следующей итерации цикла:163164```python165>>> for num in range(2, 10):166...     if num % 2 == 0:167...         print("Found an even number", num)168...         continue169...     print("Found an odd number", num)170Found an even number 2171Found an odd number 3172Found an even number 4173Found an odd number 5174Found an even number 6175Found an odd number 7176Found an even number 8177Found an odd number 9178```179180## 4.5. `pass`Инструкции181182Инструкция [`pass`](https://python-all.ru/3.8/reference/simple_stmts.html#pass) ничего не делает. Она может использоваться, когда синтаксически требуется инструкция, но программа не должна выполнять никаких действий. Например:183184```python185>>> while True:186...     pass  # Активное ожидание прерывания с клавиатуры (Ctrl+C)187...188```189190Это часто используется для создания минимальных классов:191192```python193>>> class MyEmptyClass:194...     pass195...196```197198Ещё одно место, где можно использовать [`pass`](https://python-all.ru/3.8/reference/simple_stmts.html#pass) – в качестве заполнителя для тела функции или условного оператора при работе над новым кодом, позволяя сохранять более абстрактный уровень мышления. `pass` молча игнорируется:199200```python201>>> def initlog(*args):202...     pass   # Не забудьте реализовать это!203...204```205206## 4.6. Определение функций207208Можно создать функцию, которая выводит ряд Фибоначчи до произвольной границы:209210```python211>>> def fib(n):    # вывести ряд Фибоначчи до n212...     """Вывести ряд Фибоначчи до n."""213...     a, b = 0, 1214...     while a < n:215...         print(a, end=' ')216...         a, b = b, a+b217...     print()218...219>>> # Теперь вызовите только что определённую функцию:220... fib(2000)2210 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597222```223224Ключевое слово [`def`](https://python-all.ru/3.8/reference/compound_stmts.html#def) вводит *определение* функции. За ним должны следовать имя функции и список формальных параметров в скобках. Инструкции, составляющие тело функции, начинаются со следующей строки и должны иметь отступ.225226Первый оператор тела функции может быть строковым литералом; этот строковый литерал является строкой документации функции, или *docstring*. (Подробнее о docstring можно найти в разделе [Строки документации](https://python-all.ru/3.8/tutorial/controlflow.html#tut-docstrings).) Существуют инструменты, которые используют docstring для автоматического создания онлайн- или печатной документации, или чтобы позволить пользователю интерактивно просматривать код; рекомендуется включать docstring в код, который вы пишете, так что сделайте это привычкой.227228*Выполнение* функции вводит новую таблицу символов, используемую для локальных переменных функции. Точнее, все присваивания переменных в функции сохраняют значение в локальной таблице символов; тогда как обращения к переменным сначала ищут в локальной таблице символов, затем в локальных таблицах символов объемлющих функций, затем в глобальной таблице символов и, наконец, в таблице встроенных имён. Таким образом, глобальные переменные и переменные объемлющих функций не могут быть напрямую присвоены внутри функции (если только, для глобальных переменных, они не указаны в операторе [`global`](https://python-all.ru/3.8/reference/simple_stmts.html#global), или, для переменных объемлющих функций, в операторе [`nonlocal`](https://python-all.ru/3.8/reference/simple_stmts.html#nonlocal)), хотя на них можно ссылаться.229230The 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.8/tutorial/controlflow.html#id2) When a function calls another function, or calls itself recursively, a new local symbol table is created for that call.231232Определение функции связывает имя функции с объектом функции в текущей таблице символов. Интерпретатор распознаёт объект, на который указывает это имя, как определённую пользователем функцию. Другие имена также могут указывать на тот же объект функции и использоваться для доступа к функции:233234```python235>>> fib236<function fib at 10042ed0>237>>> f = fib238>>> f(100)2390 1 1 2 3 5 8 13 21 34 55 89240```241242Приходя из других языков, вы можете возразить, что `fib` – это не функция, а процедура, поскольку она не возвращает значение. На самом деле даже функции без оператора [`return`](https://python-all.ru/3.8/reference/simple_stmts.html#return) возвращают значение, хотя и довольно скучное. Это значение называется `None` (это встроенное имя). Запись значения `None` обычно подавляется интерпретатором, если оно было бы единственным записанным значением. Вы можете увидеть его, если действительно захотите, с помощью [`print()`](https://python-all.ru/3.8/library/functions.html#print):243244```python245>>> fib(0)246>>> print(fib(0))247None248```249250Просто написать функцию, которая возвращает список чисел ряда Фибоначчи, вместо того чтобы выводить его:251252```python253>>> def fib2(n):  # возвращает ряд Фибоначчи до n254...     """Возвращает список, содержащий ряд Фибоначчи до n."""255...     result = []256...     a, b = 0, 1257...     while a < n:258...         result.append(a)    # см. ниже259...         a, b = b, a+b260...     return result261...262>>> f100 = fib2(100)    # вызов263>>> f100                # вывод результата264[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]265```266267Этот пример, как обычно, демонстрирует некоторые новые возможности Python:268269- Оператор [`return`](https://python-all.ru/3.8/reference/simple_stmts.html#return) возвращает значение из функции. `return` без выражения-аргумента возвращает `None`. Завершение функции без явного возврата также возвращает `None`.270- Оператор `result.append(a)` вызывает *метод* объекта списка `result`. Метод – это функция, которая «принадлежит» объекту и имеет имя `obj.methodname`, где `obj` – некоторый объект (это может быть выражение), а `methodname` – имя метода, определённого типом объекта. Разные типы определяют разные методы. Методы разных типов могут иметь одинаковые имена без неоднозначности. (Можно определять собственные типы объектов и методы, используя *классы*; см. [Классы](https://python-all.ru/3.8/tutorial/classes.html#tut-classes)). Метод `append()`, показанный в примере, определён для объектов списка; он добавляет новый элемент в конец списка. В этом примере он эквивалентен `result = result + [a]`, но более эффективен.271272## 4.7. Подробнее об определении функций273274Также можно определять функции с переменным числом аргументов. Существует три формы, которые можно комбинировать.275276### 4.7.1. Значения аргументов по умолчанию277278Наиболее полезная форма – указать значение по умолчанию для одного или нескольких аргументов. Это создаёт функцию, которую можно вызывать с меньшим количеством аргументов, чем она определена допускать. Например:279280```python281def ask_ok(prompt, retries=4, reminder='Please try again!'):282    while True:283        ok = input(prompt)284        if ok in ('y', 'ye', 'yes'):285            return True286        if ok in ('n', 'no', 'nop', 'nope'):287            return False288        retries = retries - 1289        if retries < 0:290            raise ValueError('invalid user response')291        print(reminder)292```293294Эту функцию можно вызывать несколькими способами:295296- передавая только обязательный аргумент: `ask_ok('Do you really want to quit?')`297- передавая один из необязательных аргументов: `ask_ok('OK to overwrite the file?', 2)`298- или даже передавая все аргументы: `ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')`299300Этот пример также вводит ключевое слово [`in`](https://python-all.ru/3.8/reference/expressions.html#in). Оно проверяет, содержит ли последовательность определённое значение.301302Значения по умолчанию вычисляются в точке определения функции в *определяющей* области видимости, так что303304```python305i = 5306307def f(arg=i):308    print(arg)309310i = 6311f()312```313314выведет `5`.315316**Важное предупреждение:** Значение по умолчанию вычисляется только один раз. Это имеет значение, когда значение по умолчанию является изменяемым объектом, таким как список, словарь или экземпляры большинства классов. Например, следующая функция накапливает аргументы, переданные ей при последующих вызовах:317318```python319def f(a, L=[]):320    L.append(a)321    return L322323print(f(1))324print(f(2))325print(f(3))326```327328Это выведет329330```python331[1]332[1, 2]333[1, 2, 3]334```335336Если вы не хотите, чтобы значение по умолчанию разделялось между последующими вызовами, вы можете написать функцию так:337338```python339def f(a, L=None):340    if L is None:341        L = []342    L.append(a)343    return L344```345346### 4.7.2. Именованные аргументы347348Функции также можно вызывать с помощью [именованных аргументов](https://python-all.ru/3.8/glossary.html#term-keyword-argument) вида `kwarg=value`. Например, следующая функция:349350```python351def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):352    print("-- This parrot wouldn't", action, end=' ')353    print("if you put", voltage, "volts through it.")354    print("-- Lovely plumage, the", type)355    print("-- It's", state, "!")356```357358принимает один обязательный аргумент (`voltage`) и три необязательных аргумента (`state`, `action` и `type`). Эту функцию можно вызывать любым из следующих способов:359360```python361parrot(1000)                                          # 1 позиционный аргумент362parrot(voltage=1000)                                  # 1 именованный аргумент363parrot(voltage=1000000, action='VOOOOOM')             # 2 именованных аргумента364parrot(action='VOOOOOM', voltage=1000000)             # 2 именованных аргумента365parrot('a million', 'bereft of life', 'jump')         # 3 позиционных аргумента366parrot('a thousand', state='pushing up the daisies')  # 1 позиционный, 1 именованный367```368369но все следующие вызовы будут недопустимы:370371```python372parrot()                     # отсутствует обязательный аргумент373parrot(voltage=5.0, 'dead')  # неименованный аргумент после именованного374parrot(110, voltage=220)     # дублирование значения для одного и того же аргумента375parrot(actor='John Cleese')  # неизвестный именованный аргумент376```377378В вызове функции именованные аргументы должны следовать за позиционными. Все переданные именованные аргументы должны соответствовать одному из аргументов, принимаемых функцией (например, `actor` не является допустимым аргументом для функции `parrot`), и их порядок не важен. Это также включает необязательные аргументы (например, `parrot(voltage=1000)` тоже допустим). Ни один аргумент не может получать значение более одного раза. Вот пример, который завершается ошибкой из-за этого ограничения:379380```python381>>> def function(a):382...     pass383...384>>> function(0, a=0)385Traceback (most recent call last):386  File "<stdin>", line 1, in <module>387TypeError: function() got multiple values for keyword argument 'a'388```389390Когда присутствует последний формальный параметр вида `**name`, он принимает словарь (см. [Отображения – dict](https://python-all.ru/3.8/library/stdtypes.html#typesmapping)), содержащий все именованные аргументы, кроме тех, которые соответствуют формальному параметру. Это можно комбинировать с формальным параметром вида `*name` (описано в следующем подразделе), который принимает [кортеж](https://python-all.ru/3.8/tutorial/datastructures.html#tut-tuples), содержащий позиционные аргументы, выходящие за пределы списка формальных параметров. (`*name` должен находиться перед `**name`.) Например, если мы определим функцию так:391392```python393def cheeseshop(kind, *arguments, **keywords):394    print("-- Do you have any", kind, "?")395    print("-- I'm sorry, we're all out of", kind)396    for arg in arguments:397        print(arg)398    print("-" * 40)399    for kw in keywords:400        print(kw, ":", keywords[kw])401```402403Её можно было бы вызвать так:404405```python406cheeseshop("Limburger", "It's very runny, sir.",407           "It's really very, VERY runny, sir.",408           shopkeeper="Michael Palin",409           client="John Cleese",410           sketch="Cheese Shop Sketch")411```412413и, конечно, она выведет:414415```text416-- Do you have any Limburger ?417-- I'm sorry, we're all out of Limburger418It's very runny, sir.419It's really very, VERY runny, sir.420----------------------------------------421shopkeeper : Michael Palin422client : John Cleese423sketch : Cheese Shop Sketch424```425426Обратите внимание, что порядок, в котором выводятся именованные аргументы, гарантированно соответствует порядку, в котором они были указаны в вызове функции.427428### 4.7.3. Специальные параметры429430По умолчанию аргументы функции Python могут передаваться либо по позиции, либо явно по ключевому слову. Для удобочитаемости и производительности имеет смысл ограничить способ передачи аргументов, чтобы разработчику достаточно было взглянуть на определение функции и определить, передаются ли элементы по позиции, по позиции или по ключевому слову, или только по ключевому слову.431432Определение функции может выглядеть так:433434```text435def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):436      -----------    ----------     ----------437        |             |                  |438        |        Positional or keyword   |439        |                                - Keyword only440         -- Positional only441```442443где `/` и `*` являются необязательными. Если они используются, эти символы указывают на вид параметра в зависимости от того, как аргументы могут передаваться функции: только по позиции, по позиции или ключевому слову и только по ключевому слову. Параметры, передаваемые по ключевому слову, также называют именованными параметрами.444445#### 4.7.3.1. Аргументы, передаваемые по позиции или по ключевому слову446447Если `/` и `*` отсутствуют в определении функции, аргументы могут передаваться функции по позиции или по ключевому слову.448449#### 4.7.3.2. Параметры только по позиции450451Рассмотрим это подробнее: можно пометить некоторые параметры как *только по позиции*. Если параметры *только по позиции*, их порядок имеет значение, и их нельзя передавать по ключевому слову. Параметры только по позиции помещаются перед `/` (прямая косая черта). Символ `/` используется для логического отделения параметров только по позиции от остальных. Если в определении функции нет `/`, то параметров только по позиции нет.452453Параметры, следующие после `/`, могут быть *позиционными или ключевыми* или *только по ключевому слову*.454455#### 4.7.3.3. Аргументы только по ключевому слову456457Чтобы пометить параметры как *только по ключевому слову* (то есть они должны передаваться только как именованные аргументы), поместите `*` в списке аргументов непосредственно перед первым *только по ключевому слову* параметром.458459#### 4.7.3.4. Примеры функций460461Рассмотрим следующие примеры определений функций, обращая особое внимание на маркеры `/` и `*`:462463```python464>>> def standard_arg(arg):465...     print(arg)466...467>>> def pos_only_arg(arg, /):468...     print(arg)469...470>>> def kwd_only_arg(*, arg):471...     print(arg)472...473>>> def combined_example(pos_only, /, standard, *, kwd_only):474...     print(pos_only, standard, kwd_only)475```476477Первое определение функции, `standard_arg`, наиболее привычная форма, не накладывает ограничений на способ вызова, и аргументы могут передаваться по позиции или по ключевому слову:478479```python480>>> standard_arg(2)4812482483>>> standard_arg(arg=2)4842485```486487Вторая функция `pos_only_arg` ограничена использованием только позиционных параметров, так как в определении функции присутствует `/`:488489```python490>>> pos_only_arg(1)4911492493>>> pos_only_arg(arg=1)494Traceback (most recent call last):495  File "<stdin>", line 1, in <module>496TypeError: pos_only_arg() got an unexpected keyword argument 'arg'497```498499Третья функция `kwd_only_args` допускает только именованные аргументы, на что указывает `*` в определении функции:500501```python502>>> kwd_only_arg(3)503Traceback (most recent call last):504  File "<stdin>", line 1, in <module>505TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given506507>>> kwd_only_arg(arg=3)5083509```510511И последняя использует все три способа вызова в одном определении функции:512513```python514>>> combined_example(1, 2, 3)515Traceback (most recent call last):516  File "<stdin>", line 1, in <module>517TypeError: combined_example() takes 2 positional arguments but 3 were given518519>>> combined_example(1, 2, kwd_only=3)5201 2 3521522>>> combined_example(1, standard=2, kwd_only=3)5231 2 3524525>>> combined_example(pos_only=1, standard=2, kwd_only=3)526Traceback (most recent call last):527  File "<stdin>", line 1, in <module>528TypeError: combined_example() got an unexpected keyword argument 'pos_only'529```530531Наконец, рассмотрим такое определение функции, где возможно пересечение между позиционным аргументом `name` и `**kwds`, у которого `name` является ключом:532533```python534def foo(name, **kwds):535    return 'name' in kwds536```537538Не существует вызова, который заставил бы её вернуть `True`, поскольку ключевое слово `'name'` всегда будет привязано к первому параметру. Например:539540```python541>>> foo(1, **{'name': 2})542Traceback (most recent call last):543  File "<stdin>", line 1, in <module>544TypeError: foo() got multiple values for argument 'name'545>>>546```547548Но при использовании `/` (аргументы только по позиции) это возможно, поскольку он позволяет передать `name` как позиционный аргумент, а `'name'` как ключ в именованных аргументах:549550```python551def foo(name, /, **kwds):552    return 'name' in kwds553>>> foo(1, **{'name': 2})554True555```556557Иными словами, имена позиционных параметров (только по позиции) можно использовать в `**kwds` без неоднозначности.558559#### 4.7.3.5. Итог560561Сценарий использования определяет, какие параметры использовать в определении функции:562563```python564def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):565```566567В качестве рекомендации:568569- Используйте параметры только по позиции, если вы не хотите, чтобы имена параметров были доступны пользователю. Это полезно, когда имена параметров не имеют реального значения, если нужно принудительно задать порядок аргументов при вызове функции или если требуется принимать некоторые позиционные параметры вместе с произвольными ключевыми словами.570- Используйте параметры только по ключевому слову, когда имена имеют значение, и определение функции становится более понятным благодаря явному указанию имён, или если вы хотите предотвратить зависимость пользователей от порядка передаваемых аргументов.571- Для API используйте параметры только по позиции, чтобы избежать разрушительных изменений API, если в будущем имя параметра будет изменено.572573### 4.7.4. Произвольные списки аргументов574575Наконец, наименее часто используемая возможность – указать, что функцию можно вызывать с произвольным количеством аргументов. Эти аргументы будут упакованы в кортеж (см. [Кортежи и последовательности](https://python-all.ru/3.8/tutorial/datastructures.html#tut-tuples)). Перед переменным числом аргументов может быть ноль или более обычных аргументов.576577```python578def write_multiple_items(file, separator, *args):579    file.write(separator.join(args))580```581582Обычно эти аргументы `variadic` находятся последними в списке формальных параметров, потому что они собирают все остальные входные аргументы, переданные функции. Любые формальные параметры, которые следуют после `*args` параметра, являются аргументами, передаваемыми только по ключевому слову, то есть они могут использоваться только как ключевые, а не позиционные аргументы.583584```python585>>> def concat(*args, sep="/"):586...     return sep.join(args)587...588>>> concat("earth", "mars", "venus")589'earth/mars/venus'590>>> concat("earth", "mars", "venus", sep=".")591'earth.mars.venus'592```593594### 4.7.5. Распаковка списков аргументов595596Обратная ситуация возникает, когда аргументы уже находятся в списке или кортеже, но их нужно распаковать для вызова функции, требующей отдельных позиционных аргументов. Например, встроенная функция [`range()`](https://python-all.ru/3.8/library/stdtypes.html#range) ожидает отдельные аргументы *start* и *stop*. Если они недоступны по отдельности, запишите вызов функции с оператором `*`, чтобы распаковать аргументы из списка или кортежа:597598```python599>>> list(range(3, 6))            # обычный вызов с отдельными аргументами600[3, 4, 5]601>>> args = [3, 6]602>>> list(range(*args))            # вызов с аргументами, распакованными из списка603[3, 4, 5]604```605606Аналогично, словари могут передавать именованные аргументы с помощью оператора `**`:607608```python609>>> def parrot(voltage, state='a stiff', action='voom'):610...     print("-- This parrot wouldn't", action, end=' ')611...     print("if you put", voltage, "volts through it.", end=' ')612...     print("E's", state, "!")613...614>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}615>>> parrot(**d)616-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !617```618619### 4.7.6. Лямбда-выражения620621Небольшие анонимные функции можно создать с помощью ключевого слова [`lambda`](https://python-all.ru/3.8/reference/expressions.html#lambda). Эта функция возвращает сумму двух своих аргументов: `lambda a, b: a+b`. Лямбда-функции можно использовать везде, где требуются объекты функций. Синтаксически они ограничены одним выражением. Семантически это просто синтаксический сахар для обычного определения функции. Как и вложенные определения функций, лямбда-функции могут ссылаться на переменные из содержащей области видимости:622623```python624>>> def make_incrementor(n):625...     return lambda x: x + n626...627>>> f = make_incrementor(42)628>>> f(0)62942630>>> f(1)63143632```633634В приведённом выше примере лямбда-выражение используется для возврата функции. Другое применение – передача небольшой функции в качестве аргумента:635636```python637>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]638>>> pairs.sort(key=lambda pair: pair[1])639>>> pairs640[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]641```642643### 4.7.7. Строки документации644645Вот некоторые соглашения о содержании и форматировании строк документации.646647Первая строка всегда должна быть кратким и сжатым описанием назначения объекта. Для краткости в ней не следует явно указывать имя или тип объекта, так как они доступны другими способами (кроме случая, когда имя оказывается глаголом, описывающим действие функции). Эта строка должна начинаться с заглавной буквы и заканчиваться точкой.648649Если в строке документации есть несколько строк, вторая строка должна быть пустой, чтобы визуально отделить краткое описание от остальной части. Последующие строки должны быть одним или несколькими абзацами, описывающими соглашения о вызове объекта, его побочные эффекты и т.д.650651Парсер Python не удаляет отступы из многострочных строковых литералов в Python, поэтому инструменты, обрабатывающие документацию, должны при необходимости удалять отступы. Это делается по следующему соглашению. Первая непустая строка *после* первой строки строки определяет величину отступа для всей строки документации. (Первую строку мы не можем использовать, так как она обычно примыкает к открывающим кавычкам строки, и её отступ не очевиден в строковом литерале.) Затем пробельные символы, «эквивалентные» этому отступу, удаляются из начала всех строк строки. Строки с меньшим отступом встречаться не должны, но если они встречаются, все их начальные пробелы должны быть удалены. Эквивалентность пробелов следует проверять после замены табуляции (обычно на 8 пробелов).652653Вот пример многострочной строки документации:654655```python656>>> def my_function():657...     """Ничего не делает, но документирует.658...659...     Нет, правда, он ничего не делает.660...     """661...     pass662...663>>> print(my_function.__doc__)664Do nothing, but document it.665666    No, really, it doesn't do anything.667```668669### 4.7.8. Аннотации функций670671[Аннотации функций](https://python-all.ru/3.8/reference/compound_stmts.html#function) – это полностью необязательная метаинформация о типах, используемых пользовательскими функциями (см. [**PEP 3107**](https://python-all.ru/3.8/tutorial/controlflow.html) и [**PEP 484**](https://python-all.ru/3.8/tutorial/controlflow.html) для получения дополнительной информации).672673[Аннотации](https://python-all.ru/3.8/glossary.html#term-function-annotation) хранятся в атрибуте `__annotations__` функции в виде словаря и не влияют ни на какую другую часть функции. Аннотации параметров задаются двоеточием после имени параметра, за которым следует выражение, вычисляющее значение аннотации. Аннотации возвращаемых значений задаются литералом `->`, за которым следует выражение, между списком параметров и двоеточием, обозначающим конец инструкции [`def`](https://python-all.ru/3.8/reference/compound_stmts.html#def). В следующем примере аннотированы обязательный аргумент, необязательный аргумент и возвращаемое значение:674675```python676>>> def f(ham: str, eggs: str = 'eggs') -> str:677...     print("Annotations:", f.__annotations__)678...     print("Arguments:", ham, eggs)679...     return ham + ' and ' + eggs680...681>>> f('spam')682Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}683Arguments: spam eggs684'spam and eggs'685```686687## 4.8. Интермеццо: Стиль кодирования688689Теперь, когда вы собираетесь писать более длинные и сложные программы на Python, самое время поговорить о *стиле кодирования*. Большинство языков можно писать (или, точнее, *форматировать*) в разных стилях; одни стили более читаемы, чем другие. Облегчить чтение вашего кода другим – всегда хорошая идея, и принятие хорошего стиля кодирования в этом очень помогает.690691Для Python [**PEP 8**](https://python-all.ru/3.8/tutorial/controlflow.html) стал руководством по стилю, которому следуют большинство проектов; он продвигает очень читаемый и приятный глазу стиль кодирования. Каждый разработчик Python должен прочитать его в какой-то момент; вот наиболее важные моменты, извлечённые для вас:692693- Используйте отступы в 4 пробела и никаких табуляций.694695  4 пробела – хороший компромисс между маленьким отступом (позволяет большую глубину вложенности) и большим отступом (легче читать). Табуляция вносит путаницу, и её лучше избегать.696- Переносите строки так, чтобы они не превышали 79 символов.697698  Это помогает пользователям с маленькими экранами и позволяет размещать несколько файлов с кодом рядом на больших экранах.699- Используйте пустые строки для разделения функций и классов, а также крупных блоков кода внутри функций.700- По возможности размещайте комментарии на отдельных строках.701- Используйте строки документации.702- Используйте пробелы вокруг операторов и после запятых, но не непосредственно внутри скобочных конструкций: `a = f(1, 2) + g(3, 4)`.703- Давайте классам и функциям согласованные имена; принято использовать `UpperCamelCase` для классов и `lowercase_with_underscores` для функций и методов. Всегда используйте `self` в качестве имени первого аргумента метода (см. [Первый взгляд на классы](https://python-all.ru/3.8/tutorial/classes.html#tut-firstclasses) для получения дополнительной информации о классах и методах).704- Не используйте экзотические кодировки, если ваш код предназначен для использования в международной среде. Стандартная кодировка Python, UTF-8 или даже обычный ASCII в любом случае подходят лучше всего.705- Аналогично, не используйте символы, не входящие в ASCII, в идентификаторах, если есть хоть малейшая вероятность, что код будут читать или сопровождать люди, говорящие на другом языке.706707Сноски708709**[1](https://python-all.ru/3.8/tutorial/controlflow.html#id1)**710711На самом деле, *вызов по ссылке на объект* было бы лучшим описанием, поскольку если передаётся изменяемый объект, вызывающий увидит любые изменения, вносимые вызываемым (например, элементы, добавленные в список).712