Python основан на принципах структурного программирования.
1. Следует отказаться от использования оператора безусловного перехода goto.
2. Любая программа строится из трёх базовых управляющих конструкций: последовательность, ветвление, цикл.
3. В программе базовые управляющие конструкции могут быть вложены друг в друга произвольным образом.
4. Повторяющиеся фрагменты программы можно оформить в виде подпрограмм.
5. Каждую логически законченную группу инструкций следует оформить как блок.
6. Все конструкции должны иметь один вход (в начале) и один выход (в конце).
7. Разработка программы ведётся пошагово, методом «сверху вниз».
Группа конструкций в Python, имеющих одинаковый отступ, образуют блок, **последовательность** . Операторы в ней выполняются последовательно, выход одного оператора соединен со входом следующего.
Блоки вложенных конструкций должны иметь больший отступ.
Пустой блок записывается как ``pass`` (пропуск), так как блок должен содержать хотя бы один оператор. Чаще всего оператор ``pass`` используется в случае, когда код этой части программы ещё не написан.
Обязательность отступов в Python повышает наглядность программы и позволяет обходиться без схем алгоритмов при разработке.
Рекомендуется писать один оператор в строке, но можно написать несколько операторов через ``;`` (считается, что остальные операторы в строке имеют тот же отступ, что и первый оператор), а слишком длинный оператор можно разбить на несколько строк, указав в конце строки ``\``:
```run-python
import math
a=float(input()); b=float(input()); c=float(input()) # ввод 3 чисел как строк и преобразование во float
# площадь треугольника по 3 сторонам
S=(a+b+c)*(a+b-c)* \
(b+c-a)*(a-b+c)
print(math.sqrt(S/16))
<<
3
4
5
```
### Ветвление
Разветвляющийся алгоритм — алгоритм, в котором действия выполняются по одной возможных ветвей решения задачи в зависимости от некоторого условия.
Оператор ``if`` выполняет указанный блок, если условие истинно.
`tt"if" quad "условие" tt":" quad "блок"`
```run-python
import math
# Найти угол по значению cos
a=float(input())
if -1<=a<=1:
print(math.acos(a))
<<
0.5
```
Оператор ``if-else`` выполняет `"блок"_1`, если условие истинно, иначе выполняет `"блок"_2`
```run-python
import math
# Найти угол по значению cos
a=float(input())
if -1<=a<=1:
print(math.acos(a))
else:
print(f"Значение {a} не входит в диапазон [-1;1]")
<<
0.5
```
Вместо вложенных ``if-else`` нужно использовать дополнительные ветки ``elif``:
```run-python
# Соответствие российских размеров одежды и международных
s=int(input())
if s<=40:
if s<=38: print("X", end='') # вывод без перехода на новую строку
print("XS")
elif s<=44:
print("S")
elif s<=48:
print("M")
elif s<=52:
print("L")
elif s<=58:
print("XL")
else:
print("XXL")
<<
50
```
Если в качестве условия выполняется сравнение переменной с ограниченным набором значений или выяснение ее типа, то можно использовать специальный оператор ``match``, который выбирает одну из веток, помеченных ``case``.
Выражение проверяется по порядку, сверху-вниз на соответствие образцу и дополнительному ограничению в `tt"if" quad "условие"`, если оно указано. Когда подходящая ветка будет найдена, выполняется блок в этой ветке и выполнение конструкции заканчивается. Образец ``_`` соответствует любому значению и может быть указан только в последней ветке в конструкции.
Образец может быть как простым значением, так и кортежем, списком, словарем, объектом и может содержать
* константы -- соответствующая часть выражения будет проверена на соответствие типа и равенство значений;
* набор констант через ``|`` -- проверка на равенство одному из вариантов, можно дополнительно указать `tt"as" quad "имя"` для сохранения этой части выражения в переменной;
* `"имя"` -- переменной `"имя"` будет присвоено значение, если эта часть не нужна, то вместо имени можно указать ``_``;
* `"тип"("имя")` -- выражение быть проверено на соответствие типу перед присваиванием переменной.
```run-python
# Соответствие российских размеров одежды и международных
s=int(input())
match s:
case 38: print("XXS")
case 40: print("XS")
case 42|44: print("S")
case 46|48: print("M")
case 50|52: print("L")
case 54|56|58: print("XL")
case _: print("XXL")
<<
50
```
Можно выделить начальную часть кортежа или списка, часть словаря (но не множества), а оставшуюся часть поместить в переменную с помощью `bb"*" "имя"` для кортежа или списка и `bb"**" "имя"` для словаря.
```run-python
x=[1,7,"a","b"]
match x:
case int(n) if n in range(10): print("маленькое число")
case int(_): print("целое число")
case str(s):
print(f"строка длиной {len(s)}")
case _,_: print("кортеж из 2")
case (float(_),float(_),float(_)): print("кортеж из 3 вещественных чисел")
case [1|2|3 as a,int(b),*ost] if len(ost)<=2: print(f"хороший список начинается с {a},{b}")
case list(_): print("плохой список")
```
### Циклы
Циклический алгоритм — алгоритм, в котором некоторая часть действий (тело цикла) выполняется многократно.
Оператор ``while`` повторяет указанное действие, пока условие истинно. ``while`` используется, когда количество итераций неизвестно заранее.
`tt"while" quad "условие" tt":" quad "блок"`
```run-python
# Найти НОД(a,b)
a=int(input())
b=int(input())
while b!=0:
a,b=b,a%b
print(a)
<<
30
12
```
Более сложный пример с вложенными циклами:
```run-python
# Разложение числа N на простые множители
n=int(input())
i=2
while i*i<=n:
while n%i==0:
print(i, end=' ')
n/=i;
i+=1
if n>1: print(n, end=' ')
print("")
<<
250
```
Цикл ``for`` используется, когда заранее известно количество итераций, или необходимо выполнить действия с каждым элементом последовательности, коллекции, генератора или результатом функции-генератора.
```run-python
for i in range(10): # 10 итераций, от 0 до 9
print(i)
for i in [10,25,4,7,11]: # по значениям из списка
print(i)
d={'a':100,7:25, 'name': 'abc'}
for k in d: # по ключам словаря
print(k, d[k])
s="string"
for i,c in enumerate(s): # добавляем индекс к значениям последовательности
print(i, c)
```
После оператора цикла можно написать\
`tt"else:" quad "блок"`\
Операторы блока выполнятся при успешном завершении цикла (условие ``while`` станет ложным или будет достигнут конец последовательности).
Внутри блока цикла можно написать операторы:
* ``continue`` -- перейти к следующей итерации цикла;
* ``break`` -- завершить цикл досрочно, при этом операторы в блоке ``else`` не выполняются.
```run-python
a = [1, 3, 5, 7, 9, 11]
val = 7
for i,v in enumerate(a):
if v == val:
print(f"Найден в позиции {i}")
break
else:
print("Не найден")
```
Цикл по точкам с целыми координатами внутри круга радиусом r:
```run-python
import math
r=4
# с помощью генератора
for p in ((x,y) for x in range(-r,r+1) for y in range(-math.isqrt(r*r-x*x),math.isqrt(r*r-x*x)+1)):
print(p)
# вложенным for
for x in range(-r,r+1):
for y in range(-math.isqrt(r*r-x*x),math.isqrt(r*r-x*x)+1):
print((x,y))
```
### Обработка ошибок
Программа на Python сначала компилируется и могут быть выявлены синтаксические ошибки (пропущена скобка, неправильный отступ и т.д.), а затем выполняется и может быть обнаружена ошибка времени исполнения (деление на ноль, неправильный тип аргумента функции и т.д.). Выполнение программы при этом завершается и выводится сообщение. Если ошибка произошла из-за неправильной информации, введенной пользователем, то должна быть возможность изменить ввод без завершения программы.
```run-python
n=int(input())
print(n**2)
<<
five
```
Для обработки ошибок времени исполнения используется оператор ``try``:
Части ``except``, ``else``, ``finally`` являются опциональными.
`"блок"_i` выполняется тогда, когда происходит ошибка `"типа"_i`, информация об ошибке помещается в переменную, указанную после ``as``. `"блок"_e` выполняется только тогда, когда `"блок"_t` выполнился до конца без ошибок, ``return`` или ``break/continue``. `"блок"_f` выполняется всегда, даже при завершении `"блок"_t` по ошибке, ``return`` или ``break/continue``.
```run-python
while True:
try:
n=int(input())
except EOFError: exit() # завершение программы, если конец ввода
except ValueError as err: print(f"Ошибка {err}, повторите ввод")
else: break # успешный ввод, завершение цикла
print(n**2)
<<
five
5
```
Оператор ``raise`` используется для порождения ошибок (исключительных ситуаций, исключений):\
`tt"raise" quad "выражение"`
Если ошибка произойдет в строке 2, то переменной ``f`` не будет присвоено значение и выполнение ``f.close()`` будет ошибкой. Для таких ситуаций рекомендуется использовать оператор ``with``:\
`tt"with" quad "выражение" quad tt"as" quad "переменная" tt":" quad "блок"`\
или\
`tt"with" quad "выражение" tt":" quad "блок"`
Для результата выражения вызывается метод ``__enter__`` и результат метода присваивается указанной переменной, если она указана в назначении ``as``. После завершения блока, независимо от успешности, вызывается метод ``__exit__`` для результата выражения. Можно указать несколько выражений или назначений ``as`` через запятую.
```python #
with open('input.txt','r') as f:
n=int(f.readline())
...
# для файла метод __exit__ выполняет закрытие
```