Другие конструкции
Часто основными конструкциями в Python называют немного не то, что мы рассмотрели в первой части. К ним относят что-то вроде конструкций с ключевым словом if, for, while и так далее. Мы же сейчас более подробно смотрим на то, как устроен язык, и основными называем более абстрактные конструкции, вроде statement и expression. Но во второй части мы рассмотрим и обычные конструкции, причём рассмотрим их так, чтобы изученное нами ранее помогало нам понимать, как они работают (будем применять то самое переиспользование смысла, упомянутое в первой части).
Указание: возможно, после освоения первой части стоит сделать перерыв в пару дней, вспомнить её и уже потом переходить ко второй.
Последовательности statement
Посмотрим на такой код
def test():
print("Testing...")
print("Done!")
print("Hello")Как мы уже знаем, любой код на Python состоит из последовательности statement. И выполнение кода означает последовательное выполнение каждого из statement. В данном случае это def statement и expression statement.
Но разве...
def test():
print("Testing...")
print("Done!")
print("Hello")Вот это не два expression statement? Да, это действительно они. Правда они относятся к уже другой последовательности statement.
В этом коде у нас две последовательности statement. Первая последовательность основная, и statement из неё выполняются непосредственно в рамках выполнения программы.
А вот вторая последовательность statement относится к содержимому def statement, и к ней уже не относится последовательное выполнение при запуске программы. Более того, в этой программе данная последовательность statement никогда не будет выполнена. Но давайте добавим в конец программы вот этот текст:
test()Так мы добавили в основную последовательность ещё один statement: expression statement. При выполнении программы мы доходим до этого expression statement, и в рамках его выполнения вычисляем expression test(), смысл которого как раз и состоит в выполнении нашей второй последовательности statement.
Теперь давайте введём термин для языковой конструкции, которая соответствует вот этим самым перечислениям statement. Просто чтобы не писать всегда перечисление statement.
И тут есть нюанс. Если мы посмотрим в раздел официальной документации Python про составные statement, мы увидим, что для обозначения перечислений statement всей программы используется термин file_input, а для других перечислений statement используется термин suite.
Почему не назвать и то, и то одинаково, например просто statements, и использовать его и для всего файла, и для отдельных последовательностей? Дело в том, что есть некоторые отличия между последовательностью во всём файле и отдельной последовательностью. Но они нам сейчас не так важны. Поэтому мы будем использовать два термина, но и первый, и второй будут пока что для нас означать любую последовательность языковых конструкций statement.
Рассмотрим вот такой код
for i in range(100):
print("Ok")
if i % 2 == 0:
print(i)Вопрос: сколько тут последовательностей statement? Правильный ответ такой: тут их 3 штуки.
- Первая
file_input, именно она просто последовательно выполняется при запуске программы. И в ней есть толькоfor statement, всё. - Вторая
suite, которая является частьюfor statement, содержит дваstatement:expression statementиif statement. - Третья
suite, которая является частьюif statement, содержит одинstatement:expression statement.
Далее будут в упрощённом виде изложены некоторые конструкции, использующие suite.
def statement
"def" name "(" parameters ")" ":" suiteКавычки используются, чтобы обозначить, что буквально этот текст используется при записи конструкции. То есть вы не можете написать def statement без использования текста def, и так далее. Когда кавычек нет, имеется в виду ссылка на какую-то другую конструкцию. Под name тут имеется в виду любое корректное имя, под parameters имеется в виду любой корректный список параметров функции, под suite имеется в виду любая корректная последовательность statement. Мы не будем сейчас подробно рассматривать некоторые конструкции вроде parameters.
Смысл выполнения этого statement:
- Создать объект типа
function, который содержит в себе данную последовательностьstatementи информацию о параметрах, указанную вparameters. - Связать этот объект с именем
name.
if statement
"if" expression ":" suite
["elif" expression ":" suite]
["else" ":" suite]Квадратные скобки используются, чтобы указать, что эта часть языковой конструкции необязательна. Вот пример, в котором использованы только обязательные части
if 1 == 1:
print("Hello")Вот пример, где дополнительно использована одна необязательная часть
if 1 == 1:
print("Hello")
else:
print("Not hello")Смысл выполнения этого statement:
- Если результат вычисления первого
expression— это объект, который считается истиной (например объектTrue), то выполняем первыйsuite - Если результат первого
expressionоказался ложным, и у нас есть блокelif, то вычисляем следующийexpressionи, если он истинен, выполняемsuite. - Если результаты всех
expressionоказались ложными, и у нас есть блокelse, выполняем последнийsuite.
И, кроме этого, блоков elif может быть много. Соответственно, описанные выше грамматика и смысл упрощены. Но, скорее всего, вам уже интуитивно понятно, что происходит, если добавляется ещё один блок elif: в цепочке появляется дополнительная проверка expression и в случае, если результат истинен, выполняется соответствующий suite, на чём выполнение всего if statement заканчивается.
while statement
"while" expression ":" suiteСмысл выполнения этого statement:
- Вычисляем
expression. Если результат вычисления истинен, выполняемsuite - Вычисляем
expression. Если результат вычисления истинен, выполняемsuite - И так далее. Если в какой-то момент
expressionоказался ложным, выполнениеwhile statementзаканчивается.
for statement
"for" name "in" expression ":" suiteСмысл выполнения этого statement:
- Вычисляем
expression. - Связываем имя
nameс первым элементом результата вычисления (если в результате вычисления в принципе элементов не может быть, например у него типint, то произойдёт ошибка). - Выполняем
suite. - Связываем имя
nameсо вторым элементом результата вычисления. - Выполняем
suite. - И так далее, пока элементы не закончатся.
Примечание: если в результате вычисления expression получился объект, у которого в принципе могут быть элементы, но их количество равно нулю, то наш suite никогда не будет выполнен.
Задания
Задание 1
Укажите, сколько в этом коде языковых конструкций suite. Выпишите все statement из этого кода
print("Hello")
def test():
a = print("...")
print(a)
result = test()
print(result)Запустите код и посмотрите, что он выведет. Почему так?
Задание 2
Выпишите все statement и все expression из этого кода.
lst = ["Mihail", "Alex"]
for i in lst:
print(i)
if True:
print("Oh...")
elif i == "Mihail":
print("Hello, Mihail!")Также укажите, в соответствии с выполнением какой инструкции из file_input будет вычислен каждый из этих expression. Есть ли такие expression, которые никогда не будут вычислены? Какие и почему?
Задание 3
lst = [1]
for i in lst:
lst.append(1)
print(i)Что выводит этот код? Закончится ли когда-то выполнение этого кода? Обоснуйте свой ответ, используя изученный материал.
Ответьте на те же вопросы и для этого кода
lst = []
for i in lst:
lst.append(1)
print(i)Задание 4
Напишите функцию, которая принимает два списка и выводит их как таблицу, как показано в примере.
Как примерно должен выглядеть правильный def statement
def print_two_lists(lst_1, lst_2):
pass # тут statements реализующие нужный вывод в консольКстати, pass — это отдельный вид statement, смысл которого просто в том, чтобы занять место, при его выполнении ничего не происходит. Поэтому его можно писать и в suite (как тут), и в file_input.
Пример входных данных (элементов в списках может быть сколько угодно)
Пример вывода в терминал
| Hello | Test |
| Bye | Test 2 |Указание: попробуйте подумать о том, какие в конечном итоге должны произойти побочные эффекты, о том, какие expression для этого должны быть вычислены, и о наборе различных statement, которые мы можем применить. Задача фактически состоит в том, чтобы собрать такой suite, выполнение которого вызовет нужные побочные эффекты.
Напомню, как можно вывести строку в консоль без переноса строки:
print(text, end="")Если не помните что-то конкретное про используемые объекты (например, как получать длину списка), можете гуглить.
Во время выполнения задания можно (и нужно) проверять свои гипотезы относительно того, как работает ваш код через его запуск. Главное при этом стараться не действовать наугад, а анализировать результат и обдумывать дальнейшие действия.
Задание 5
Доработайте код из предыдущего задания. Нужно, чтобы он выводил таблицы вот так:
| ----- | ------ |
| Hello | Test |
| ----- | ------ |
| Bye | Test 2 |
| ----- | ------ |