Л11. Python як друга мова: перенесення мислення
Коротко про лекцію
Перенесемо вже сформоване алгоритмічне мислення у Python. Розберемо модель імен та об’єктів, відступи, керування потоком, зворотне трасування стека та інтерактивний стан виконання.
Після десяти лекцій ви вже вмієте будувати алгоритм і трасувати стан. Тому Python не починає курс заново. Ми переносимо знайомі ідеї у новий синтаксис. Головне питання лекції: що зберігається, а що змінюється?
У C++ тип змінної задавав важливі обмеження. Python працює з іменами та об’єктами інакше. Також блоки коду позначаються відступами. Наприкінці лекції додамо інтерактивний стан, який залежить від порядку запуску фрагментів коду.
Практична мета. Після лекції ви повинні читати короткий Python-код, передбачати його стан і відтворювати інтерактивне виконання з чистого старту.
1. Алгоритм переживає зміну мови
Розглянемо знайому задачу. Є ціна одиниці та кількість. Треба знайти повну вартість.
Спочатку сформулюємо алгоритм мовою даних:
взяти ціну
взяти кількість
помножити їх
показати результат
У Python ім’я створюється присвоєнням name = value. Ліворуч записане ім’я, праворуч — значення або вираз. Крапка з комою наприкінці не потрібна.
У Python print(...) — стандартна функція для виведення. Значення в дужках передається функції як аргумент.
price = 12.5
quantity = 3
total = price * quantity
print(total)
Алгоритм не змінився. Змінився спосіб запису. Стан після третього рядка містить три потрібні імена.
flowchart TD
A["price = 12.5"] --> B["quantity = 3"]
B --> C["total = price * quantity"]
C --> D["print(total)"]
Спробуйте перед запуском змінити quantity на 4. Спочатку передбачте результат. Потім перевірте прогноз у інтерактивному прикладі.
2. Ім’я посилається на об’єкт
У Python ім’я зв’язується з об’єктом. Нове присвоєння може зв’язати те саме ім’я з іншим об’єктом.
Термін: переприв’язування
Переприв’язування змінює об’єкт, на який посилається ім’я. Попередній об’єкт від цього не перетворюється на новий.
Об’єкт у Python — це значення разом із його типом. Ім’я дає програмі спосіб звернутися до об’єкта. Присвоєння зв’язує ім’я з результатом правої частини.
Той самий запис присвоєння може пізніше зв’язати ім’я з іншим об’єктом. Таку зміну зв’язку називають переприв’язуванням. Старий об’єкт через це не перетворюється на новий.
value = 12
print(value)
value = "готово"
print(value)
Після першого присвоєння value посилається на ціле число. Після другого — на рядок. Python не оголошує ім’я як int назавжди.
flowchart TD
N["ім’я value"] --> I["об’єкт 12"]
N2["ім’я value після повторного присвоєння"] --> S["об’єкт 'готово'"]
Це не означає, що Python «не має типів». Типи мають самі об’єкти. Операції все одно повинні бути змістовними для конкретних типів.
3. Відступ є частиною структури програми
У C++ межі блока позначали фігурні дужки. Python позначає блок однаковим відступом. Двокрапка після умови відкриває блок.
temperature = 19
if temperature >= 18:
print("комфортно")
else:
print("прохолодно")
Обидва print мають відступ, бо належать своїм гілкам. Рядок без такого відступу вже буде поза блоком. Тому форматування тут впливає на виконання.
Для кількох взаємовиключних гілок Python має слово elif. Воно відповідає знайомій ідеї else if.
score = 82
if score >= 90:
print("відмінно")
elif score >= 75:
print("добре")
else:
print("потрібне повторення")
flowchart TD
A{"score >= 90?"} -- так --> B["відмінно"]
A -- ні --> C{"score >= 75?"}
C -- так --> D["добре"]
C -- ні --> E["потрібне повторення"]
Під час читання дивіться на дві речі: умову та рівень відступу. Разом вони визначають шлях виконання.
3.1. input() переносить знайому ідею стандартного вводу
У C++ ми читали дані через std::cin. Python має функцію input(), яка показує запрошення та повертає введений текст. Отже результат input() спочатку має тип str, навіть якщо користувач ввів цифри.
Термін: input()
input(prompt) читає один рядок від користувача й повертає його як str. Для числових обчислень текст треба явно перетворити, наприклад через int(...).
Введіть -5. Потім повторіть запуск із 8 і простежте, як те саме розгалуження реагує на інше значення.
temperature_text = input("Температура: ")
temperature = int(temperature_text)
if temperature < 0:
print("мороз")
else:
print("не нижче нуля")
Перший рядок отримує текст. Другий створює ціле число з цього тексту. Якщо замість числа ввести абв, перетворення завершиться помилкою. Таку ситуацію навчимося обробляти у Л13.
4. for обходить готову послідовність значень
У C++ цикл for часто містив лічильник, умову та зміну. Python зазвичай формулює обхід безпосередньо.
Запис for item in sequence: означає: взяти черговий елемент послідовності, зв’язати його з item і виконати блок. Після блока цикл переходить до наступного елемента.
Коли потрібні послідовні цілі числа, зручно використати range. Виклик range(1, 5) дає для обходу числа 1, 2, 3, 4. Права межа 5 не входить до послідовності.
total = 0
for minute in range(1, 5):
total += minute
print(total)
Трасування зручно вести таблицею стану:
minute |
total після додавання |
|---|---|
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
Тут += має знайомий зміст: взяти попереднє значення, додати праву частину і переприв’язати ім’я.
5. while лишається циклом за умовою
Цикл while продовжує роботу, доки умова істинна. Перед кожною ітерацією Python знову обчислює умову. Тому змінні стану мають наближати цикл до завершення.
balance = 100
deposit = 250
while balance < 1000:
balance += deposit
print(balance)
Початковий баланс дорівнює 100. Кожна ітерація додає 250. Після досягнення 1100 умова стає хибною, тому цикл завершується.
Правило трасування не змінилося після C++: знайдіть стан, умову та зміну стану. Синтаксис коротший, а причинність та сама.
6. Істинність об’єкта скорочує деякі перевірки
Булеві значення True і False у Python зберігають знайомий сенс. Порівняння теж утворюють логічний результат.
Python також дозволяє перевіряти істинність об’єкта. Порожній рядок поводиться як хибне значення в умові. Непорожній рядок — як істинне.
Термін: істинність об’єкта
Істинність об’єкта — правило, за яким Python трактує об’єкт у логічній умові. Порожні значення часто є хибними, а непорожні — істинними.
message = ""
if message:
print("є текст")
else:
print("порожньо")
Такий запис доречний, коли питання звучить як «чи є дані?». Якщо потрібне точне порівняння, записуйте його явно.
Python записує знайомі логічні оператори словами. and вимагає істинності обох частин. or вимагає істинності хоча б однієї частини. not заперечує логічний результат.
Ці слова читаються майже як частина речення. Проте пріоритет операцій усе одно має значення. Складні умови краще розкладати на зрозумілі частини.
7. Зворотне трасування стека показує шлях до помилки
Програма може пройти синтаксичну перевірку й зламатися під час виконання. У такому випадку середовище показує зворотне трасування стека. Це ланцюжок місць виклику, який приводить до рядка помилки.
Як читати зворотне трасування стека
Починайте з останнього рядка: він називає тип помилки та її повідомлення. Потім рухайтеся вище до останнього рядка вашого коду.
Типовий вигляд повідомлення:
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
Читайте зворотне трасування стека знизу. Останній рядок називає тип проблеми. Вище шукайте свій файл і конкретний рядок коду.
У наступному прикладі ми не створюємо помилку. Замість цього перевіряємо небезпечну межу до ділення.
distance = 120
speed = 60
if speed == 0:
print("швидкість не може дорівнювати нулю")
else:
print(distance / speed)
Змініть speed на 0 і передбачте гілку. Потім приберіть перевірку у власній копії та прочитайте повідомлення. Мета — навчитися діагностувати причину, а не боятися повідомлення про помилку.
8. Інтерактивне виконання має власний стан
Зошит — документ, у якому текст і код організовані в окремі комірки. Код виконує ядро — активний процес Python, який зберігає створені імена між запусками комірок.
Терміни: зошит і ядро
Зошит зберігає комірки документа, а ядро виконує код і тримає поточний стан Python. Перезапуск ядра очищає цей стан.
Кожна виконана комірка може створити або переприв’язати імена. Ці зміни залишаються в активному ядрі до його перезапуску.
Комірка може використати ім’я, створене раніше. Проблема виникає, коли потрібну комірку виконували лише випадково. Тоді зошит працює у вашій поточній сесії, але не відтворюється з чистого старту.
flowchart TD
A["чисте ядро"] --> B["комірка 1: створює data"]
B --> C["комірка 2: змінює data"]
C --> D["комірка 3: читає data"]
D --> E["результат залежить від порядку"]
Для перевірки відтворюваності використовуйте правило:
Restart
→ Run All зверху вниз
→ перевірити всі результати
Команда Restart очищає попередній стан ядра. Команда Run All відновлює його лише з коду зошита. Якщо після цього виникла помилка, залежність від прихованого стану стала видимою.
9. Як переносити знайому конструкцію
Під час переходу між мовами корисно не запам’ятовувати таблицю символів. Починайте з ролі конструкції.
| Питання алгоритму | C++ | Python |
|---|---|---|
| вибір гілки | if / else if / else |
if / elif / else |
| цикл за умовою | while |
while |
| обхід значень | for (...) |
for item in ... |
| логічне І | && |
and |
| логічне АБО | || |
or |
| виведення | std::cout |
print(...) |
Спочатку сформулюйте, що має зробити алгоритм. Потім вибирайте синтаксис мови. Так перенесення знань лишається керованим.
10. Контрольний спосіб читання Python-коду
Для короткої програми працюйте у такому порядку:
- позначте початкові імена та об’єкти;
- знайдіть умови й межі блоків за відступом;
- простежте переприв’язування імен;
- для циклу випишіть значення кожної ітерації;
- передбачте виведення;
- лише потім запускайте код;
- у зошиті перевірте
Restart → Run All.
Такий порядок переносить навичку трасування з C++. Python додає іншу модель імен і стан зошита. Алгоритмічне мислення лишається спільною основою.
11. Інтерактивна самоперевірка лекції
Самоперевірка вимагає трасувати переприв’язування, відступи, цикли та порядок виконання комірок. Частина питань містить короткий код, який треба передбачити до запуску.