Posted on :: Source Code::

Языковая конструкция.

Давайте приведём пример текста, написанного на языке Python, для которого мы уже заранее знаем, что он корректен и имеет смысл.

print(1 + 1)

Но как мы определили, что этот текст корректен (мы знаем что Python его запустит) и имеет смысл (мы можем сказать, что он сделает)? Если вы просто помните, что вот такой код нормальный, но не можете объяснить почему именно Python считает его нормальным, вам будет полезно понять почему так происходит.

На самом деле, определить, является ли текст корректной программой на Python просто. Он должен соответствовать всего одному условию:

Текст программы на Python должен содержать последоватлеьность инструкций.

Точка. Если текст не содержит последовательность инструкций, он не будет являться корректной программой на Python. И соответсвенно не мы, не Python, не буем в состоянии понять что вообще он значит. Например, что значит фраза на русском языке Я по я нож телефон? Она не соответсвует правилам языке, и поэтому мы не понимаем её смысл. Вроде отдельные слова мы понимаем, но смысл не появляется от этого. Так и тут, если нет соответсвия этому правилу, никакого смысла у программы не будет.

Но что вообще это правило значит? Что такое инструкция, что значит последовательность? Как проверить, соответсвует ли текст этому правилу?

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

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

Python имеет понимать конкретные языковые конструкции. Запомните этот термин.

Языковой конструкцией мы называем правила, в соответсвии с которыми какая-то часть программы считается правильной и имеет смысл.

Давайте по порядку разберём все языковые конструкции которые нужно знать, чтобы полностью понять, почему имеено такой текст корректен и имеет смысл, а, например

print(= 1 + 1)
print() = [1]
def () "Hello"

Некорректны, и следовательно не имеют никакого смысла (мы вообще не можем понять что это такое, не говоря про то, чтобы вспомнить, что это значит).

Начнём с начала. С языковой конструкции, которая отвечает за весь файл в целом.

Что вообще можно писать в файле? Этот вопрос может показаться очень обширным, но мы сейчас аккуратно ответим на него. Любой файл может содержать только перечисление инструкций. Ничего другого он содержать не может. Если в файле будет что-то кроме перечисления инструкций, это будет некорретный файл, не имеющий смысла.

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

+ 1
test = a
[0]
print(hello)

Тут у нас есть переносы строк, и чтобы он был корректным, мы должны убедиться, что

Единственная языковая конструкция, которая имеет смысл, когда вы пишите программу на Python -- это statement. Вся программа на Python всегда является перечислением конструкций statement.

Выражения

Давайте научимся понимать, что является выражением в Python, а что не является.

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

Посмотрим на такую программу

1 + 1

Весь текст этой программы является выражением. Но как мы это определили? Запомните: отличительной чертой выражений является то, что когда выполнение программы доходит до них, они вычисляются, и в результате вычисления в оперативной памяти появляется объект. Кажется, очевидно, что 1 плюс 1 даст нам двойку, верно? И именно так можно понять, что часть текста программы 1 + 1 тут является выражением.

Рассмотрим другой пример.

a = 1 + 1

Что тут является выражением? Возьмём такой фрагмент

= 1 +

По такому фрагменту неясно, что вообще имеется ввиду. Он не имеет какого-то устойчивого смысла. И соответсвенно ни выражением, ни чем-то другим, мы называть его не можем.

Возьмём какой-то другой фрагмент текста программы

1 + 1

О, ну это собсвенно то что мы рассматривали выше. Да, этот фрагмент является выражением.

a = 1 + 1

Вот мы взяли тест всей программы. Это корректная конструкция, имеющая смысл. Является ли этот фрагмент выражением?

Нет, не является, и это нужно просто запомнить.

Так, куски программы, которые мы можем отдельно понять, и для которых мы понимаем как их можно вычислить, получив в результате какой-то объект, мы называем выражениями. Какие-то обрывки, не имеющие смысла, мы никак не можем назвать. Куски, имеющие смысл, но в результате выполнения которых мы не получаем какой-то конкретный объект в качестве результата вычисления, мы так же не называем выражениями.

Но как тогда называть корректные куски текста программы, которые не являются выражениями? Есть много языковых конструкций которые не являются выражениями, и каждую из них нужно отдельно помнить.

Например вот присваивание:

name = expression

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

Вот объявление функции:

def name(args):
    a = 1
    return a

Смысл всей конструкции в последовательном выполнении следующих шагов:

  1. Создание нового объекта: функции, которая содержит действия, заданные внутри этой конструкции.
  2. Привязка этого только-что созданного объекта к имени name.

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

Определения

Объект — это данные, лежащие в оперативной памяти. Данные объекта состоят из двух комопнентов: тип и значение.

Данные объекта:

  1. Тип
  2. Значение

Тип нельзя изменить. Значение можно, но не в любом объекте.

Выражение в Python -- это любая языковая конструкция, если не сказано иначе. Есть особые типы языковых конструкций, и всё, кроме них, в Python является выражением.

Выражения обладают следующими свойствами:

  1. Когда выполнение программы доходит до него, оно вычисляется, в результате чего в оперативной памяти появляется объект.
  2. В процессе их вычисления может быть вызвана функция.
  3. В процессе их вычисления могут быть вызваны побочные эффекты.

На Python можно программировать используя только выржения. Например вот это программа в которой есть только выражение:

1 + 2

Пройдёмся по пунктам.

  1. В момент когда

Объект -- это область в памяти,

Задания

Задание 1

name = "Tom"
age = 20

message = name + " is " + str(age)
age = age + 1
name = name + " Smith"

final_message = name + " is " + str(age)

Попробуйте самостоятельно подробно объяснить, что происходит на каждой строке:

  1. Какие объекты вычисляются (с какими типами и значениями)?
  2. Какие переменные создаются? Какие переменные начинают ссылаться на другой объект?
  3. На какие объекты ссылаются переменные name, age, message и final_message после каждой строки?
  4. Изменяется ли какой-нибудь уже существующий объект?

Задание 2

Напишите несколько программ на Python.

Ниже приведены картинки, на которых изображено состояние программы. Вы должны для каждой картинки написать хотя бы две программы, которые приводят именно к такому состоянию.

Пример

Тут мы видим, что есть два имени. Первое имя ссылается на объект типа list, в значении имеющий две ссылки: на объект с типом int и значением 1, и на объект с типом int и значением 2. Второе имя ссылается на тот же самый объект типа list.

К примеру, вот такой код приведёт к нужной нам ситуации:

items = [1, 2]
alias = items

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

items = [1]  # есть список, есть имя которое на него ссылается
items.append(2)  # изменили список, теперь он такой как нужен
alias = items  # теперь на него ссылается второе нужное имя
items = [1]  # то же самое
alias = items  # сразу сделали второе имя
alias.append(2)  # теперь список такой как надо
items = list()  # сделали сначала пустой список и первое нужное имя на него указывает
alias = items  # теперь на него ссылается второе нужное имя
items.extend([1, 2])  # изменили список: там теперь ссылки на все нужные объекты

Пример, где лаконичность намного хуже. Но тем не менее его результат точно такой же как у остальных:

[1, 2]  # сделали нужный список

# но никакое имя на него не указывает, так-что он сразу
#  удалился, не оказав влияния на финальное состояние

items = 1 

# используем имя, ссылающееся на единицу, чтобы сделать
#  список в котором есть ссылка на ту же единицу
items = [items]

alias = items

# используем ссылки на единицу которые у нас есть чтобы
#  получить двойку.  и изменяем список: добавляем в него 
#  ссылку на эту двойку.
alias.append(alias[0] + alias[0])

Выполнение каждого из этих фрагментов кода приводит к тому, что состояние программы становится таким, как изображено на картинке выше.

Указание: представляйте в уме или рисуйте промежуточные состояния кода который вы пишите. Финальное состояние должно быть в точности таким какое нарисовано, но промежуточные могут быть очень разными, как в этом примере.

Примечания:

  1. Вы можете двигать блоки на картинках.
  2. Вы можете навести мышку на начало или конец стрелки, чтобы понять, куда именно она указывает.
  3. Вы можете нажать Full page рядом с диаграмой чтобы развернуть её на всю страницу.

Первое состояние

Второе состояние

Третье состояние

Четвёртое состояние

Table of Contents