Posted on :: Source Code::

Другие конструкции

Часто основными конструкциями в 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:

  1. Создать объект типа function, который содержит в себе данную последовательность statement и информацию о параметрах, указанную в parameters.
  2. Связать этот объект с именем 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:

  1. Если результат вычисления первого expression — это объект, который считается истиной (например объект True), то выполняем первый suite
  2. Если результат первого expression оказался ложным, и у нас есть блок elif, то вычисляем следующий expression и, если он истинен, выполняем suite.
  3. Если результаты всех expression оказались ложными, и у нас есть блок else, выполняем последний suite.

И, кроме этого, блоков elif может быть много. Соответственно, описанные выше грамматика и смысл упрощены. Но, скорее всего, вам уже интуитивно понятно, что происходит, если добавляется ещё один блок elif: в цепочке появляется дополнительная проверка expression и в случае, если результат истинен, выполняется соответствующий suite, на чём выполнение всего if statement заканчивается.

while statement

"while" expression ":" suite

Смысл выполнения этого statement:

  1. Вычисляем expression. Если результат вычисления истинен, выполняем suite
  2. Вычисляем expression. Если результат вычисления истинен, выполняем suite
  3. И так далее. Если в какой-то момент expression оказался ложным, выполнение while statement заканчивается.

for statement

"for" name "in" expression ":" suite

Смысл выполнения этого statement:

  1. Вычисляем expression.
  2. Связываем имя name с первым элементом результата вычисления (если в результате вычисления в принципе элементов не может быть, например у него тип int, то произойдёт ошибка).
  3. Выполняем suite.
  4. Связываем имя name со вторым элементом результата вычисления.
  5. Выполняем suite.
  6. И так далее, пока элементы не закончатся.

Примечание: если в результате вычисления 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 |
| ----- | ------ |
Table of Contents