# Глава 2. Синтаксические правила
> Код, который так же понятен, как обычный английский.
Одна из целей создания питона, озвученная автором языка Гвидо ван Россумом
Рассмотрим структуру программы и основные синтаксические правила. Также вы узнаете, для чего нужны и чем различаются оператор `pass` и объект-синглтон «многоточие».
## Структура программы
В Java, go, C++ и многих других языках точкой входа в приложение является метод `main()`. Такие языки объединяет нерушимое правило: нельзя просто написать код на уровне файла и запустить его. Питон — представитель скриптовых языков, и на него это правило не распространяется: с первой же строчки скрипта может начинаться бизнес-логика, не обернутая ни в какую функцию.
Исходный код программы на питоне принято сохранять в файлах с расширением `.py`. Для запуска из консоли необходимо вызвать интерпретатор питона и первым аргументом указать имя файла. Допустим, исходный код в `example.py` состоит из одной строчки:
```python
print("Dummy script, does nothing")
```
Тогда после запуска скрипта мы увидим в консоли ожидаемый вывод:
```shell
$ python example.py
Dummy script, does nothing
```
В этом коротком примере вся программа сводится к вызову встроенной функции `print()` для вывода текста. В ней нет подключения модулей, объявления переменных, классов. Что ж, усложним код.
Пусть в консоль печатается текущее время:
```python {.example_for_playground}
from datetime import datetime
def print_time():
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Current Time:", current_time)
print_time()
```
```
Current Time: 13:19:20
```
На первой строке из модуля `datetime` импортируется одноименный объект в глобальное пространство имен программы. Затем объявляется функция `print_time()`. Внутри нее у объекта `datetime` вызывается метод `now()` для получения текущего времени; оно преобразовывается в удобный формат и печатается в консоль. На последней строке объявленная функция `print_time()` вызывается.
Пример демонстрирует общепринятую практику по **структурированию кода:** в начале файла импортируются нужные модули, затем объявляются какие-то глобальные переменные, функции и другие полезности, а в самом конце все это используется.
## Синтаксические правила
С этих правил начинают свой путь все питонисты.
**Вложенные блоки кода** отделяются отступами, а не фигурными скобками. Мы будем придерживаться [рекомендации из PEP8:](https://peps.python.org/pep-0008/#indentation) 1 отступ = 4 пробела.
Вложенному блоку предшествует инструкция, заканчивающаяся двоеточием. Перед телом цикла — это условие цикла. Перед телом `if` — условие `if`. И так далее.
Пример условия:
```python
if user_is_active:
get_next_command()
else:
close_session()
```
Пример цикла:
```python
for item in items:
process(item)
```
Пример функции:
```python
def is_long(s):
if len(s) > 79:
return "string is too long"
return "string has normal length"
```
Конец строки — это конец инструкции. Точка с запятой в конце не ставится.
Пример с последовательным вызовом двух пользовательских функций. Никаких точек с запятой:
```python
check_db_is_online()
start_transaction()
```
Инициализируйте две переменные:{.task_text}
- `a`, равную 8, на одной строке.
- `b`, равную 10, на другой.
```python {.task_source #python_chapter_0020_task_0010}
```
Синтаксис: переменная = значение {.task_hint}
```python {.task_answer}
a = 8
b = 10
```
Исправьте синтаксические ошибки в коде. {.task_text}
В данном коде используется функция `range(a, b)`, позволяющая получить последовательность от целого числа `a` до целого числа `b` не включительно. {.task_text}
```python {.task_source #python_chapter_0020_task_0020}
for i in range(1, 10); print(i);
```
Нужно заменить точку с запятой в конце цикла на двоеточие. Удалить точку с запятой после `print()` и перенести вызов `print()` на новую строку с отступом. {.task_hint}
```python {.task_answer}
for i in range(1, 10):
print(i)
```
Если инструкция не влезает в строку (например, становится длиннее рекомендованных PEP8 79 символов), ее можно разбить на несколько строк с использованием круглых скобок.
Первая строка в этом примере занимает 92 символа:
```python
while retries_count < max_retries and service_is_up and not cancelled and request_is_ready:
send_request()
```
Приведем ее в соответствие с PEP8:
```python
while (
retries_count < max_retries
and service_is_up
and not cancelled
and request_is_ready
):
send_request()
```
Разбейте условие `if` на две строки или более. {.task_text}
```python {.task_source #python_chapter_0020_task_0030}
MAX_SESSIONS = 5
MAX_QUEUE_LEN = 100
sessions_count = 9
queue_tasks = ["task1", "task2"] # Here we create list of strings
error_in_request = True
if sessions_count > MAX_SESSIONS or len(queue_tasks) > MAX_QUEUE_LEN or error_in_request:
print("Error handling request")
```
Для разбиения условия на несколько строк возьмите его в круглые скобки. {.task_hint}
```python {.task_answer}
MAX_SESSIONS = 5
MAX_QUEUE_LEN = 100
sessions_count = 9
queue_tasks = ["task1", "task2"] # Here we create list of strings
error_in_request = True
if (
sessions_count > MAX_SESSIONS
or len(queue_tasks) > MAX_QUEUE_LEN
or error_in_request
):
print("Error handling request")
```
## Исключения из правил
Из этих несложных правил есть и исключения. Но их лучше избегать, чтобы не снижать читаемость кода. Тем не менее вы можете натолкнуться на злоупотребление ими в чужом коде.
Например, несколько простых инструкций в одной строке не являются ошибкой. Друг от друга они отделяются точкой с запятой. В этом примере переменным `x` и `y` присваиваются результаты пользовательских функций:
```python
x = x_offset(); y = y_offset(); print(x, y)
```
Сделайте этот код более читабельным. Одна строка — одна инструкция. {.task_text}
```python {.task_source #python_chapter_0020_task_0040}
x = 5; y = 8; print(x, y)
```
Должно получиться 3 строки: 2 для инициализации переменных и 1 на вызов функции. {.task_hint}
```python {.task_answer}
x = 5
y = 8
print(x, y)
```
Также допустимо размещать инструкцию и ее вложенный блок на одной строке. Это сработает, если сам вложенный блок не содержит каких-то своих вложенных инструкций:
```python
while is_active: send_request()
```
Перепишите этот код, чтобы вложенный блок `while` шел на отдельной строке. {.task_text}
В коде заводится функция `send_request()`, которая затем вызывается в цикле `while`. {.task_text}
```python {.task_source #python_chapter_0020_task_0050}
def send_request():
# some business logic
return False
is_active = True
while is_active: is_active = send_request()
```
Тело цикла должно идти на отдельной строке с отступом. {.task_hint}
```python {.task_answer}
def send_request():
# some business logic
return False
is_active = True
while is_active:
is_active = send_request()
```
## Оператор pass
Бывают случаи, когда вложенный блок требуется оставить пустым. Например, ловить исключение, но не совершать дополнительных действий для его обработки:
```python
try:
send_request(data)
except Exception:
# Do nothing
```
Но пустой вложенный блок — это синтаксическая ошибка:
```
SyntaxError: unexpected EOF while parsing
```
Чтобы ее избежать, был придуман оператор `pass`. Это [ассемблеровский NOP](https://en.wikipedia.org/wiki/NOP_(code)) в мире питона. Так сказать оператор «отсутствие оператора».
Теперь синтаксической ошибки не будет:
```python
try:
send_request(data)
except Exception:
pass
```
Добавьте `pass` в цикл, чтобы устранить ошибку интерпретатора. {.task_text}
```python {.task_source #python_chapter_0020_task_0060}
n = 101
while n < 100:
```
Перед оператором `pass` не забудьте сделать отступ. {.task_hint}
```python {.task_answer}
n = 101
while n < 100:
pass
```
## Многоточие
В питоне существует объект-синглтон «многоточие», привязанный к константе с именем `Ellipsis` и литералу `...`:
```python {.example_for_playground}
print(Ellipsis)
print(...)
```
```
Ellipsis
Ellipsis
```
У многоточия несколько вариантов использования, и наиболее распространенный — это проставление вместо ключевого слова `pass`. Об остальных применениях (расширенный синтаксис срезов, аннотации типов и т.д.) мы поговорим в следующих главах.
```python
def handle_request(req):
...
```
При этом многоточие не является семантической заменой `pass`: `pass` принято проставлять в качестве индикатора намеренного отсутствия кода, а многоточие — как напоминание TBD (to be defined) при активной разработке. Например, если соответствующий блок кода планируется добавить в следующем реквесте.
## Комментарии
Однострочные комментарии начинаются с символа `#`:
```python
# TODO: refactor coords calculation
x = x_offset() # get x offset
```
Многострочные комментарии обрамляются тремя подряд идущими кавычками: двойными `"` либо одинарными `'`.
```python
"""
TODO:
refactor before release!
"""
```
```python
'''
TODO:
refactor before release!
'''
```
PEP8 рекомендует использовать для многострочных комментариев двойные кавычки.
Если многострочный комментарий следует сразу за объявлением модуля, функции, класса или метода, то он называется **docstring.** Большинство современных IDE умеют делать подсказки на основе docstring.
Пример docstring для функции:
```python
def get_coords():
"""Here we calculate x, y and transform
these coordinates to lat, lon"""
pass
```
## Резюмируем
- Блоки кода определяются двоеточием и отступами.
- Для обозначения отсутствия операции во вложенном блоке предусмотрен оператор `pass`.
- Объект-синглтон `Ellipsis` и соответствующий ему литерал `...` имеют несколько вариантов использования. Самый частый — проставление многоточия `...` вместо `pass` для маркировки мест, где кода еще нет, но планируется его дописать.
- Однострочные комментарии начинаются с символа `#`, многострочные — заключаются в тройные кавычки.
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!