Инструменты управления потоком
Помимо while
только что введенного оператора, Python использует обычные операторы управления потоком, известные из других языков, с некоторыми изменениями.
Конструкция if
Наверное самая популярная конструкция.
Используется для проверки верности утверждения. Если утверждение верное, то срабатывает код ниже. Чтобы добавить другое условие напишите elif <условие>. А чтобы выполнить код, который будет выполняться в том случае, когда другие условия не сработали, пишите else. Примеры:
>>> 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
Конструкция for
цикл for
в Python выполняет итерации по элементам любой последовательности (списку или строка), в том порядке, в котором они появляются в последовательности. Например:
>>> # Measure some strings: ... words = ['cat', 'window', 'defenestrate'] >>> for w in words: ... print(w, len(w)) ... cat 3 window 6 defenestrate 12
Итерация - это единичное выполнение тела цикла. В этом примере тело цикла - print(w, len(w))
Функция range()
Если вам нужно перебрать последовательность чисел, вам пригодится встроенная функция range():
>>> for i in range(5): ... print(i) ... 0 1 2 3 4
Конечная точка последовательности не берется, т. к. итерация начинается с нуля.
Также в функции range() можно задавать начально значение и шаг:
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()
>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for num, val in enumerate(a): ... print(num, val) ... 0 Mary 1 had 2 a 3 little 4 lamb
Странная вещь случается, если вы просто печатаете диапазон:
>>> print(range(10)) range(0, 10)
Во многих отношениях возвращаемый объект range()
ведет себя как список, но на самом деле это не так. Это объект, который возвращает последовательные элементы желаемой последовательности, когда вы выполняете итерацию, но на самом деле не создает список, тем самым экономя пространство.
Мы говорим, что такой объект является итеративным , то есть пригодным в качестве цели для функций и конструкций, которые ожидают чего-то, из чего они могут получить последовательные элементы, пока не будет исчерпан запас. Мы видели, что for
оператор является такой конструкцией, в то время как пример функции, которая принимает итеративный sum()
:
>>> sum(range(4)) # 0 + 1 + 2 + 3 6
Позже мы увидим больше функций, которые возвращают итерируемые аргументы и принимают их как аргументы. Наконец, может быть, вам интересно, как получить список из диапазона. Вот решение:
>>> list(range(4)) [0, 1, 2, 3]
Операторы break и continue, а также пункт else в циклах
Оператор 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, в случае исчерпания всех итераций в цикле for или когда условие будет ложным в цикле while. Но else не работает с оператором 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
оператору.)
Оператор break используется, чтобы пропустить итерацию цикла:
>>> for num in range(2, 10): ... if num % 2 == 0: ... print("Found an even number", num) ... continue ... print("Found a number", num) Found an even number 2 Found a number 3 Found an even number 4 Found a number 5 Found an even number 6 Found a number 7 Found an even number 8 Found a number 9
Оператор pass
pass
Оператор не делает ничего. Его можно использовать, когда оператор требуется синтаксически, но программа не требует никаких действий. Например:
>>> while True: ... pass # Busy-wait for keyboard interrupt (Ctrl+C) ...
Это обычно используется для создания минимальных классов:
>>> class MyEmptyClass: ... pass ...
Другое место pass
может использоваться как заполнитель для функции или условного тела, когда вы работаете над новым кодом, что позволяет вам продолжать думать на более абстрактном уровне. pass
Молча игнорируется:
>>>
>>> def initlog(*args): ... pass # Главное не забыть! ...
Объявление функций
Мы можем создать функцию, которая записывает ряд Фибоначчи в произвольную границу:
>>> def fib(n): # написать ряд Фибоначчи до n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') ... a, b = b, a+b ... print() ... >>> # Теперь вызываем нашу функцию: ... fib(2000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Ключевое слово def
вводит определение функции . За ним должно следовать имя функции и заключенный в скобки список формальных параметров. Операторы, которые формируют тело функции, начинаются со следующей строки и должны иметь отступ.
>>> def name(): # создаем функцию ... pass #тело функции
Первым оператором тела функции может быть строковый литерал; этот строковый литерал является строкой документации функции или строкой документации .
>>> def name(): # создаем функцию ... """Строка документации""" ... pass #тело функции
Все созданные в функции переменные являются локальными и могут использоваться только в это функции. Но если у вас уже есть глобальная переменная с таким именем, то на локальную перменную питон полит болт. Но есть выход, напишите global var, чтобы сделать вашу переменную глобальной:
>>> global var >>> var = 1
Функциям можно передать аргументы(в скобочках). Они нужны, чтобы передать значения из вне, например:
>>> def summ(a, b): ... return a + b ... >>> summ(1, 2) 3
return служит для вывода из функции. После него код в функции не учитывается
Определение функции связывает имя функции с объектом функции в текущей таблице символов. Интерпретатор распознает объект, на который указывает это имя, как определенную пользователем функцию. Другие имена также могут указывать на тот же объект функции и также могут использоваться для доступа к функции:
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 0 1 1 2 3 5 8 13 21 34 55 89
Больше об объявлении функций
Также возможно определить функции с переменным числом аргументов. Есть три формы, которые можно комбинировать.
Значение аргументов по умолчанию
Наиболее полезная форма - указать значение по умолчанию для одного или нескольких аргументов. Это создает функцию, которую можно вызывать с меньшим количеством аргументов, чем это разрешено. Например:
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
Ключевые аргументы
Функции также можно вызывать, используя ключевые аргументы формы 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 позиционный аргумент parrot(voltage=1000) # 1 ключевой аргумент parrot(voltage=1000000, action='VOOOOOM') # 2 ключевых аргумента parrot(action='VOOOOOM', voltage=1000000) # 2 ключевых аргумента parrot('a million', 'bereft of life', 'jump') # 3 позиционных аргумента parrot('a thousand', state='pushing up the daisies') # 1 позиционный и 1 ключевой аргументы
но все следующие вызовы будут недействительными:
parrot() # отсутствует обязательный аргумент parrot(voltage=5.0, 'dead') # неключевой аргумент после ключевого parrot(110, voltage=220) # 2 значения одному аргументу parrot(actor='John Cleese') # неизвестный ключевой аргумент
В вызове функции ключевые слова должны следовать после позиционных аргументов. Все передаваемые ключевые слова должны соответствовать одному из аргументов, принятых функцией (например, 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
, он получает словарь , содержащий все ключевые аргументы, кроме тех, которые соответствуют формальному параметру. Это может быть объединено с формальным параметром формы *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
Обратите внимание, что порядок, в котором печатаются аргументы ключевого слова, гарантированно соответствует порядку, в котором они были предоставлены при вызове функции.
Особые параметры
По умолчанию аргументы могут передаваться в функцию Python либо по положению, либо явно по ключевому слову. Для удобочитаемости и производительности имеет смысл ограничить способ передачи аргументов, так что разработчику нужно только взглянуть на определение функции, чтобы определить, передаются ли элементы по позиции, позиции или ключевому слову или по ключевому слову.
Определение функции может выглядеть так:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): ----------- ---------- ---------- | | | | Positional or keyword | | - Keyword only -- Positional only
где /
и не *
являются обязательными. Если эти символы используются, они указывают тип параметра в зависимости от того, как аргументы могут передаваться в функцию: только для позиционных аргументов, для позиционных или ключевых аргументов и только для ключевых аргументов Параметры ключевых слов также называются именованными параметрами.
Позиционные или Ключевые аргументы
Если /
и *
нет в определении функции, аргументы могут быть позиционными или ключевыми
Только Позиционные аргументы
Рассматривая это более подробно, можно пометить некоторые параметры как только позиционные. Только позиционные параметры помещаются перед /
(косой чертой). /
Используются для логического разделения позиционных параметров только от остальных параметров. Если /
нет в определении функции, то нет только позиционных параметров.
Параметры, следующие за, /
могут быть позиционными или ключевыми словами или только ключевыми словами .
Только Ключевые аргументы
Чтобы пометить параметры как только ключевые слова , указав, что параметры должны передаваться по аргументу ключевого слова ставим *
перед ними
Примеры функций
Рассмотрим следующие примеры определений функций, уделяющих пристальное внимание маркерам /
и *
:
>>> 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
без двусмысленности.
Вывод
- Используйте только позиционные аргументы, если вы хотите, чтобы имя параметров было недоступно для пользователя. Это полезно, когда имена параметров не имеют реального значения, если вы хотите установить порядок аргументов при вызове функции или если вам нужно взять некоторые позиционные параметры и произвольные ключевые слова.
- Используйте только ключевые аргументы, когда имена имеют значение, а определение функции более понятно, если явно указывать имена или если вы хотите, чтобы пользователи не полагались на позицию передаваемого аргумента.
- Для API используйте только позиционные аргументы, чтобы предотвратить нарушение API, если имя параметра будет изменено в будущем.
Произвольные списки аргументов
Наконец, наименее часто используемый параметр - указать, что функцию можно вызывать с произвольным числом аргументов.
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'
Распаковка списков аргументов
Обратная ситуация возникает, когда аргументы уже находятся в списке или кортеже, но их необходимо распаковать для вызова функции, требующей отдельных позиционных аргументов. Например, встроенная range()
функция ожидает отдельные аргументы start и stop .
>>> list(range(3, 6)) # нормальный вызов [3, 4, 5] >>> args = [3, 6] >>> list(range(*args)) # вызов с помощью распакованных аргументов [3, 4, 5]
Таким же образом словари могут передавать аргументы ключевых слов с помощью **
оператора -o:
>>> 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 !
Lambda-функции
lambda-фунции - это те же функции, но написанные более коротко. Служат для упрощения кода. Но крайне не рекомендуется использовать их вместо больших функций, делай тем самым код нечитабельным.
>>> summ = lambda x, y: x + y >>> summ(1, 2) 3
Другое использование 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')]
Строка-описание
>>> 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.
Аннотации функции
Аннотации функций являются полностью необязательной информацией метаданных о типах, используемых пользовательскими функциями (см.ПКП 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'
Стиль кодинга
Теперь, когда вы собираетесь писать более длинные и сложные части Python, самое время поговорить о стиле кодирования . Большинство языков могут быть написаны (или более кратки, отформатированы ) в разных стилях; некоторые из них более читабельны, чем другие. Хорошей идеей всегда будет сделать так, чтобы другие могли легко читать ваш код, и принятие хорошего стиля кодирования очень помогает в этом.
Для Python PEP 8 стал руководством по стилю, которого придерживается большинство проектов; это продвигает очень читаемый и приятный для глаз стиль кодирования. Каждый разработчик Python должен прочитать его в какой-то момент; Вот самые важные моменты, извлеченные для вас:
- Используйте 4 пробела, место табов.
- 4 пробела являются хорошим компромиссом между малым отступом (допускает большую глубину вложения) и большим отступом (легче для чтения). Табы вносят путаницу, и их лучше не использовать(или натроить свою IDE так, чтобы табы превращались в пробелы).
- Переносите строки так, чтобы они не превышали 79 символов.
- Это помогает пользователям с маленькими дисплеями и позволяет иметь несколько файлов кода рядом на больших дисплеях.
- Используйте пустые строки для разделения функций и классов, а также большие блоки кода внутри функций.
- Когда это возможно, оставляйте комментарии в отдельной строке.
- Используйте строки документации.
- Используйте пробелы вокруг операторов и после запятых, но не непосредственно в скобки конструкции:
a = f(1, 2) + g(3, 4)
- Назовите свои классы и функции последовательно; Соглашение должно использовать
UpperCamelCase
для классов иlowercase_with_underscores
для функций и методов. Всегда используйтеself
в качестве имени для первого аргумента метода класса. - Не используйте причудливые кодировки, если ваш код предназначен для использования в международных средах. По умолчанию Python, UTF-8 или даже простой ASCII работают лучше всего в любом случае.
- Аналогично, не используйте символы, не входящие в ASCII, в идентификаторах, если существует лишь малейшая вероятность того, что люди, говорящие на другом языке, прочитают или сохранят код.
Заключение
В этом посте очень много странных и непонятных слов. Если вы что-то не поняли, то не волнуйтесь. В процессе обучения вы обязательно поймете это
Пост создан для тг-канала @coolcoders