Spec-Zone.ru › Python 3.8

Более сложные инструменты управления потоком

Помимо оператора while, который только что был представлен, Python использует обычные операторы управления потоком, известные из других языков программирования, с некоторыми особенностями.

4.1. if операторы

Возможно, наиболее известным типом оператора является оператор if. Например:

>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
...     x = 0
...     print('Negative changed to zero')
... elif x == 0:
...     print('Zero')
... elif x == 1:
...     print('Single')
... else:
...     print('More')
...
More

Может быть ноль или более операторов elif, и часть else является необязательной. Ключевое слово ‘elif’ является сокращением от ‘else if’ и полезно для избежания чрезмерной вложенности. Последовательность if … elif … elif … служит заменой операторам switch или case, которые встречаются в других языках.

4.2. for операторы

Оператор for в Python немного отличается от того, к чему вы привыкли в C или Pascal. Вместо того, чтобы всегда итерироваться по арифметической прогрессии чисел (как в Pascal), или предоставляя пользователю возможность определять шаг итерации и условие остановки (как в C), оператор Python for итерируется по элементам любого последовательности (списка или строки), в порядке их появления в последовательности. Например:

>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
...     print(w, len(w))
...
cat 3
window 6
defenestrate 12

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

# Strategy:  Iterate over a copy
for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

# Strategy:  Create a new collection
active_users = {}
for user, status in users.items():
    if status == 'active':
        active_users[user] = status

4.3. Функция range()

Если вам нужно итерироваться по последовательности чисел, встроенная функция range() очень полезна. Она генерирует арифметические прогрессии:

>>> for i in range(5):
...     print(i)
...
0
1
2
3
4

Указанный конечный пункт никогда не является частью сгенерированной последовательности; range(10) генерирует 10 значений, которые являются допустимыми индексами для элементов последовательности длиной 10. Можно задать начальное значение диапазона и другой шаг (даже отрицательный; иногда это называется «шагом»):

range(5, 10)
   5, 6, 7, 8, 9

range(0, 10, 3)
   0, 3, 6, 9

range(-10, -100, -30)
  -10, -40, -70

Чтобы итерироваться по индексам последовательности, можно комбинировать range() и len() следующим образом:

>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
...     print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb

Однако в большинстве таких случаев удобнее использовать функцию enumerate(), см. Методы циклической обработки.

Если просто вывести диапазон, произойдёт странная вещь:

>>> print(range(10))
range(0, 10)

Во многих отношениях объект, возвращаемый range(), ведет себя так, как если бы он был списком, но на самом деле это не так. Это объект, который возвращает последовательные элементы желаемой последовательности при итерации по нему, но фактически не создает список, что экономит память.

Мы говорим, что такой объект является итерируемым, то есть подходит в качестве целевого объекта для функций и конструкций, которые ожидают, что он будет выдавать последовательные элементы до тех пор, пока не иссякнет источник.

Мы видели, что оператор for является таким конструктом, а примером функции, которая принимает итерируемый объект, является sum():

>>> sum(range(4))  # 0 + 1 + 2 + 3
6

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

>>> list(range(4))
[0, 1, 2, 3]

В главе Структуры данных мы подробнее обсудим list().

4.4. break и continue операторы и else блоки в циклах

Оператор break, как и в C, прерывает выполнение ближайшего вложенного цикла for или while.

Операторы цикла могут иметь else блок; он выполняется, когда цикл завершается исчерпанием итерируемого объекта (for) или когда условие становится ложным (while), но не когда цикл завершается оператором break. Это иллюстрируется следующим циклом, который ищет простые числа:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

(Да, это правильный код. Внимательно посмотрите: else блок относится к оператору for, а не к оператору if.)

При использовании с циклом блок else имеет больше общего с блоком else оператора try, чем с блоком if: блок else оператора try выполняется, если исключение не возникает, а блок else цикла выполняется, если не происходит break. Подробнее об операторе try и исключениях см. Обработка исключений.

Оператор continue, также позаимствованный из C, переходит к следующей итерации цикла:

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found an odd number", num)
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9

4.5. pass операторы

Оператор pass ничего не делает. Он может использоваться, когда синтаксически требуется оператор, но программа не требует никаких действий. Например:

>>> while True:
...     pass  # Busy-wait for keyboard interrupt (Ctrl+C)
...

Это обычно используется для создания минимальных классов:

>>> class MyEmptyClass:
...     pass
...

Еще одно место, где можно использовать pass, — это заполнитель для тела функции или условного блока при работе над новым кодом, позволяя вам мыслить на более абстрактном уровне. Оператор pass будет проигнорирован:

>>> def initlog(*args):
...     pass   # Remember to implement this!
...

4.6. Определение функций

Мы можем создать функцию, которая выводит ряд Фибоначчи до произвольной границы:

>>> def fib(n):    # write Fibonacci series up to n
...     """Print a Fibonacci series up to n."""
...     a, b = 0, 1
...     while a < n:
...         print(a, end=' ')
...         a, b = b, a+b
...     print()
...
>>> # Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

Ключевое слово def вводит определение функции. За ним следует имя функции и список формальных параметров в скобках. Определяющие функцию операторы начинаются на следующей строке и должны быть отступом.

Первый оператор тела функции может необязательно быть строковой литеральной константой; эта строковая литеральная константа является строкой документации функции или строкой документации. (Подробнее о строках документации см. в разделе Строки документации.) Существуют инструменты, которые используют строки документации для автоматического создания онлайн или печатной документации или для интерактивного просмотра кода; включение строк документации в написанный код — хорошая практика, так что приучите себя к этому.

Выполнение функции создаёт новую таблицу символов, используемую для локальных переменных функции. Более точно, все присваивания значений переменным в функции хранятся в локальной таблице символов; при этом ссылки на переменные сначала ищутся в локальной таблице символов, затем в локальных таблицах символов окружающих функций, затем в глобальной таблице символов и, наконец, в таблице встроенных имён. Таким образом, глобальные переменные и переменные окружающих функций не могут быть напрямую присвоены значения в функции (если, для глобальных переменных, они не названы в операторе global, или, для переменных окружающих функций, они не названы в операторе nonlocal), хотя к ним можно обратиться.

Фактические параметры (аргументы) вызова функции вводятся в локальную таблицу символов вызываемой функции во время её вызова; таким образом, аргументы передаются по значению (где значение всегда является ссылкой на объект, а не значением объекта). 1 Когда функция вызывает другую функцию или вызывает сама себя рекурсивно, создаётся новая локальная таблица символов для этого вызова.

Определение функции связывает имя функции с объектом функции в текущей таблице символов. Интерпретатор распознаёт объект, на который указывает это имя, как функцию пользователя. Другие имена также могут указывать на тот же объект функции и могут использоваться для доступа к функции:

>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89

Если вы приходите из других языков, вы можете возразить, что fib не является функцией, а процедурой, поскольку она не возвращает значение. Фактически, даже функции без оператора return возвращают значение, хотя и довольно скучное. Это значение называется None (это встроенное имя). Интерпретатор обычно подавляет вывод значения None, если это единственное значение, которое требуется вывести. Вы можете увидеть его, если это необходимо, используя print():

>>> fib(0)
>>> print(fib(0))
None

Просто написать функцию, которая возвращает список чисел ряда Фибоначчи, а не выводит его:

>>> def fib2(n):  # return Fibonacci series up to n
...     """Return a list containing the Fibonacci series up to n."""
...     result = []
...     a, b = 0, 1
...     while a < n:
...         result.append(a)    # see below
...         a, b = b, a+b
...     return result
...
>>> f100 = fib2(100)    # call it
>>> f100                # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

Этот пример, как обычно, демонстрирует некоторые новые особенности Python:

  • Оператор return возвращает значение из функции. return без аргумента выражения возвращает None. Выход из функции без явного оператора возврата также возвращает None.
  • Оператор result.append(a) вызывает метод объекта списка result. Метод — это функция, которая «принадлежит» объекту и называется obj.methodname, где obj — некоторый объект (это может быть выражение), а methodname — имя метода, определённого типом объекта. Разные типы определяют разные методы. Методы разных типов могут иметь одинаковые имена без неоднозначности. (Можно определить собственные типы объектов и методы, используя классы, см. Классы) Метод append() в примере определён для объектов списков; он добавляет новый элемент в конец списка. В этом примере он эквивалентен result = result + [a], но более эффективен.

4.7. Дополнительная информация о определении функций

Также можно определять функции с переменным числом аргументов. Существует три формы, которые могут быть объединены.

4.7.1. Значения аргументов по умолчанию

Самая полезная форма — задание значения по умолчанию для одного или нескольких аргументов. Это создаёт функцию, которую можно вызывать с меньшим числом аргументов, чем она определена. Например:

def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)

Эту функцию можно вызывать различными способами:

  • указав только обязательный аргумент: ask_ok('Do you really want to quit?')
  • указав один из необязательных аргументов: ask_ok('OK to overwrite the file?', 2)
  • или даже указав все аргументы: ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

Этот пример также демонстрирует ключевое слово in. Оно проверяет, содержит ли последовательность определённое значение.

Значения по умолчанию вычисляются в момент определения функции в определяющей области видимости, поэтому

i = 5

def f(arg=i):
    print(arg)

i = 6
f()

выведет 5.

Важное предупреждение: значение по умолчанию вычисляется только один раз. Это имеет значение, когда значение по умолчанию — изменяемый объект, такой как список, словарь или экземпляр большинства классов. Например, следующая функция накапливает аргументы, передаваемые ей в последующих вызовах:

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

Это выведет

[1]
[1, 2]
[1, 2, 3]

Если вы не хотите, чтобы значение по умолчанию делилось между последующими вызовами, можно переписать функцию следующим образом:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

4.7.2. Аргументы по ключевому слову

Функции также можно вызывать с использованием аргументов по ключевому слову в формате kwarg=value. Например, следующая функция:

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")

принимает один обязательный аргумент (voltage) и три необязательных аргумента (state, action, и type). Эту функцию можно вызывать любым из следующих способов:

parrot(1000)                                          # 1 positional argument
parrot(voltage=1000)                                  # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword

но все следующие вызовы будут неверными:

parrot()                     # required argument missing
parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
parrot(110, voltage=220)     # duplicate value for the same argument
parrot(actor='John Cleese')  # unknown keyword argument

В вызове функции аргументы по ключевому слову должны следовать за позиционными аргументами. Все передаваемые аргументы по ключевому слову должны соответствовать одному из аргументов, принимаемых функцией (например, actor не является допустимым аргументом для функции parrot), и их порядок не важен. Это также относится к необязательным аргументам (например, parrot(voltage=1000) тоже допустим). Ни один аргумент не может получить значение более одного раза. Вот пример, который завершается ошибкой из-за этого ограничения:

>>> def function(a):
...     pass
...
>>> function(0, a=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: function() got multiple values for keyword argument 'a'

Когда присутствует последний формальный параметр в форме **name, он получает словарь (см. Типы отображения — dict), содержащий все аргументы по ключевому слову, кроме тех, которые соответствуют формальному параметру. Это можно комбинировать с формальным параметром в форме *name (описано в следующем подразделе), который получает кортеж (см. кортежи) содержащий позиционные аргументы, выходящие за рамки списка формальных параметров. (*name должен идти перед **name.) Например, если мы определим функцию так:

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])

Её можно вызвать так:

cheeseshop("Limburger", "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

и, конечно же, она выведет:

-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch

Обратите внимание, что порядок вывода аргументов по ключевому слову гарантированно соответствует порядку их предоставления в вызове функции.

4.7.3. Специальные параметры

По умолчанию аргументы могут быть переданы в Python-функцию либо по позиции, либо явно по ключевому слову. Для повышения читабельности и производительности имеет смысл ограничить способ передачи аргументов, чтобы разработчик мог определить способ передачи элементов (по позиции, по позиции или по ключевому слову, или по ключевому слову) только взглянув на определение функции.

Определение функции может выглядеть так:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
      -----------    ----------     ----------
        |             |                  |
        |        Positional or keyword   |
        |                                - Keyword only
         -- Positional only

где / и * являются необязательными. Если они используются, эти символы указывают тип параметра в зависимости от того, как аргументы могут быть переданы в функцию: только по позиции, по позиции или по ключевому слову, и только по ключевому слову. Аргументы по ключевому слову также называются именованными аргументами.

4.7.3.1. Аргументы по позиции или по ключевому слову

Если / и * отсутствуют в определении функции, аргументы могут быть переданы в функцию по позиции или по ключевому слову.

4.7.3.2. Только позиционные параметры

Рассматривая это немного подробнее, можно пометить определённые параметры как только позиционные. Если они только позиционные, порядок параметров важен, и параметры не могут быть переданы по ключевому слову. Только позиционные параметры размещаются перед / (слеш). / используется для логического разделения только позиционных параметров от остальных параметров. Если в определении функции нет /, только позиционных параметров нет.

Параметры, следующие за / могут быть позиционными или по ключевому слову или только по ключевому слову.

4.7.3.3. Только аргументы по ключевому слову

Чтобы пометить параметры как только по ключевому слову, указывая, что параметры должны передаваться по аргументу по ключевому слову, поместите * в список аргументов непосредственно перед первым параметром только по ключевому слову.

4.7.3.4. Примеры функций

Рассмотрим следующие примеры определений функций, обращая особое внимание на маркеры / и *:

>>> def standard_arg(arg):
...     print(arg)
...
>>> def pos_only_arg(arg, /):
...     print(arg)
...
>>> def kwd_only_arg(*, arg):
...     print(arg)
...
>>> def combined_example(pos_only, /, standard, *, kwd_only):
...     print(pos_only, standard, kwd_only)

В первом определении функции, standard_arg, наиболее знакомой форме, нет ограничений на вызов и аргументы могут передаваться по позиции или по ключевому слову:

>>> standard_arg(2)
2

>>> standard_arg(arg=2)
2

Во второй функции pos_only_arg ограничено использование только позиционных параметров, поскольку в определении функции есть /:

>>> pos_only_arg(1)
1

>>> pos_only_arg(arg=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got an unexpected keyword argument 'arg'

В третьей функции kwd_only_args разрешены только аргументы по ключевому слову, как указано * в определении функции:

>>> kwd_only_arg(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given

>>> kwd_only_arg(arg=3)
3

И последняя использует все три соглашения о вызовах в одном определении функции:

>>> combined_example(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given

>>> combined_example(1, 2, kwd_only=3)
1 2 3

>>> combined_example(1, standard=2, kwd_only=3)
1 2 3

>>> combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: combined_example() got an unexpected keyword argument 'pos_only'

Наконец, рассмотрим это определение функции, в котором есть потенциальное столкновение между позиционным аргументом name и **kwds, имеющим name в качестве ключа:

def foo(name, **kwds):
    return 'name' in kwds

Нет возможности выполнить вызов, который вернёт True, поскольку ключевое слово 'name' всегда будет привязано к первому параметру. Например:

>>> foo(1, **{'name': 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for argument 'name'
>>>

Но с использованием / (только позиционные аргументы) это возможно, так как позволяет name как позиционный аргумент и 'name' как ключ в аргументах по ключевому слову:

def foo(name, /, **kwds):
    return 'name' in kwds
>>> foo(1, **{'name': 2})
True

Другими словами, имена только позиционных параметров могут использоваться в **kwds без неоднозначности.

4.7.3.5. Резюме

Сценарий использования определит, какие параметры использовать в определении функции:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):

В качестве руководства:

  • Используйте только позиционные, если хотите, чтобы имена параметров не были доступны пользователю. Это полезно, когда имена параметров не имеют реального смысла, если вы хотите принудительно задать порядок аргументов при вызове функции или если вам нужно принять некоторые позиционные параметры и произвольные ключевые слова.
  • Используйте только ключевые слова, когда имена имеют значение, и определение функции более понятно, будучи явным с именами, или вы хотите предотвратить использование пользователем позиции переданного аргумента.
  • Для API используйте только позиционные, чтобы предотвратить изменения API, которые могут привести к ошибкам, если имя параметра будет изменено в будущем.

4.7.4. Списки произвольных аргументов

Наконец, наименее часто используемый вариант — указать, что функция может быть вызвана с произвольным числом аргументов. Эти аргументы будут заключены в кортеж (см. Кортежи и последовательности). Перед переменным числом аргументов может быть ноль или более обычных аргументов.

def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))

Обычно эти variadic аргументы будут последними в списке формальных параметров, поскольку они захватывают все оставшиеся входные аргументы, переданные в функцию. Любые формальные параметры, которые следуют за параметром *args, являются аргументами «только по ключевому слову», что означает, что их можно использовать только как ключевые слова, а не позиционные аргументы.

>>> def concat(*args, sep="/"):
...     return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'

4.7.5. Распаковка списков аргументов

Обратная ситуация возникает, когда аргументы уже находятся в списке или кортеже, но нужно их распаковать для вызова функции, требующего отдельных позиционных аргументов. Например, встроенная функция range() ожидает отдельные аргументы start и stop. Если они недоступны отдельно, напишите вызов функции с оператором * для распаковки аргументов из списка или кортежа:

>>> list(range(3, 6))            # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))            # call with arguments unpacked from a list
[3, 4, 5]

Аналогично, словари могут передавать аргументы по ключевому слову с помощью оператора **:

>>> def parrot(voltage, state='a stiff', action='voom'):
...     print("-- This parrot wouldn't", action, end=' ')
...     print("if you put", voltage, "volts through it.", end=' ')
...     print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

4.7.6. Выражения lambda

Небольшие анонимные функции могут быть созданы с помощью ключевого слова lambda. Эта функция возвращает сумму её двух аргументов: lambda a, b: a+b. Функции lambda могут быть использованы там, где требуются объекты функций. Они синтаксически ограничены одним выражением. Семантически, они просто синтаксический сахар для обычного определения функции. Как и определения вложенных функций, функции lambda могут ссылаться на переменные из содержащего их области видимости:

>>> def make_incrementor(n):
...     return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43

В приведенном выше примере выражение lambda используется для возвращения функции. Другое применение — передать небольшую функцию в качестве аргумента:

>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

4.7.7. Строки документации

Вот некоторые соглашения о содержании и форматировании строк документации.

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

Если в строке документации есть более одной строки, вторая строка должна быть пустой, визуально отделяя резюме от остального описания. Следующие строки должны содержать один или несколько абзацев, описывающих соглашения о вызовах объекта, его побочные эффекты и т. д.

Парсер Python не удаляет отступы из многострочных строковых литералов в Python, поэтому инструменты, обрабатывающие документацию, должны удалять отступы при необходимости. Это делается с помощью следующего соглашения. Первая непустая строка после первой строки строки определяет величину отступа для всей строки документации. (Мы не можем использовать первую строку, так как она, как правило, примыкает к открывающим кавычкам строки, поэтому её отступ не виден в строковом литерале). Пробелы, «эквивалентные» этому отступу, затем удаляются из начала всех строк строки. Строки с меньшим отступом не должны встречаться, но если они встречаются, все их начальные пробелы должны быть удалены. Эквивалентность пробелов следует проверять после расширения табуляций (обычно до 8 пробелов).

Вот пример многострочной строки документации:

>>> def my_function():
...     """Do nothing, but document it.
...
...     No, really, it doesn't do anything.
...     """
...     pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.

    No, really, it doesn't do anything.

4.7.8. Аннотации функций

Аннотации функций — это полностью необязательная метаданная информация о типах, используемых в пользовательских функциях (см. PEP 3107 и PEP 484 для получения дополнительной информации).

Аннотации хранятся в атрибуте __annotations__ функции в виде словаря и не влияют на никакую другую часть функции. Аннотации параметров определяются двоеточием после имени параметра, за которым следует выражение, вычисляющее значение аннотации. Аннотации возвращаемого значения определяются буквальным ->, за которым следует выражение, между списком параметров и двоеточием, обозначающим конец def оператора. В следующем примере есть обязательный аргумент, необязательный аргумент и аннотированное значение возвращаемого значения:

>>> def f(ham: str, eggs: str = 'eggs') -> str:
...     print("Annotations:", f.__annotations__)
...     print("Arguments:", ham, eggs)
...     return ham + ' and ' + eggs
...
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
Arguments: spam eggs
'spam and eggs'

4.8. Интермедия: Стиль кодирования

Теперь, когда вы собираетесь писать более длинные и сложные фрагменты Python, настало время поговорить о стиле кодирования. Большинство языков можно писать (или, более точно, форматировать) в разных стилях; некоторые более удобочитаемы, чем другие. Сделать код легко читаемым для других — всегда хорошая идея, и принятие приятного стиля кодирования помогает в этом огромным образом.

Для Python PEP 8 стал руководством по стилю, которому следуют большинство проектов; он способствует очень удобочитаемому и приятному стилю кодирования. Каждый разработчик Python должен его прочитать в какой-то момент; вот самые важные моменты, извлеченные для вас:

  • Используйте отступы из 4 пробелов и не используйте табуляцию.

    4 пробела — хороший компромисс между малым отступом (позволяет большую глубину вложенности) и большим отступом (легче читается). Табуляция вводит путаницу и лучше всего её избегать.

  • Обрезайте строки так, чтобы они не превышали 79 символов.

    Это помогает пользователям с небольшими дисплеями и позволяет иметь несколько файлов кода рядом на больших дисплеях.

  • Используйте пустые строки для разделения функций и классов, а также больших блоков кода внутри функций.
  • По возможности размещайте комментарии на отдельной строке.
  • Используйте строки документации.
  • Используйте пробелы вокруг операторов и после запятых, но не непосредственно внутри скобок: a = f(1, 2) + g(3, 4).
  • Называйте ваши классы и функции последовательно; соглашение состоит в использовании UpperCamelCase для классов и lowercase_with_underscores для функций и методов. Всегда используйте self в качестве имени первого аргумента метода (см. Первый взгляд на классы для получения дополнительной информации о классах и методах).
  • Не используйте сложные кодировки, если ваш код предназначен для использования в международных средах. По умолчанию Python, UTF-8 или даже обычный ASCII работают лучше в любом случае.
  • Аналогично, не используйте не-ASCII символы в идентификаторах, если есть хоть малейшая вероятность, что люди, говорящие на другом языке, будут читать или поддерживать код.

Примечания

1

На самом деле, вызов по ссылке на объект было бы лучшим описанием, так как если передаётся изменяемый объект, вызывающий код увидит любые изменения, которые делает вызываемая функция (элементы, добавленные в список).

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/tutorial/controlflow.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API