Read in other languages: English 🇺🇸,
Polska 🇵🇱, German 🇩🇪, French 🇫🇷,
Spanish 🇪🇸, Українська 🇺🇦.
Python 
Найпопулярніші запитання та відповіді на співбесіді з Python
1. Що таке Python і які його основні особливості?
#### Python
**Python** — це високорівнева мова загального призначення з акцентом на
читабельність, швидку розробку та великий стандартний інструментарій.
Основні особливості:
- **Простий синтаксис**: код легко читати й підтримувати.
- **Інтерпретована модель виконання**: швидкий цикл змін без етапу ручної
компіляції.
- **Кросплатформеність**: один код працює на Linux, macOS, Windows.
- **Мультипарадигменність**: procedural, OOP, functional підходи в одному
проєкті.
- **Сильна екосистема**: `pip`, `venv`, `pyproject.toml`, тисячі готових
бібліотек.
- **Сучасні можливості Python 3.10+**: type hints, `dataclass`, `async/await`,
`match/case`, генератори, context managers.
Приклад production-style функції:
```python
from dataclasses import dataclass
@dataclass(slots=True)
class User:
name: str
active: bool
def process_users(users: list[User]) -> list[str]:
return [user.name for user in users if user.active]
```
**Коротко:**
- Python прискорює розробку завдяки простому синтаксису та великій стандартній
бібліотеці.
- Мова підходить для backend, automation, data/ML, тестування та DevOps.
- У Python 3.10+ ключові практики: type hints, async IO, сучасний standard
library.
2. Які ключові переваги Python?
#### Python
Ключові переваги Python в продакшені:
- висока швидкість розробки через лаконічний синтаксис;
- велика стандартна бібліотека (`pathlib`, `itertools`, `collections`,
`asyncio`);
- зріла екосистема пакетів для backend, data, automation, тестування;
- переносимість коду між ОС;
- хороша підтримка типізації (`typing`, `mypy`, `pyright`) і сучасних практик.
**Коротко:**
- Python зменшує time-to-market.
- Дає багато готових інструментів без додаткових залежностей.
- Підходить і для MVP, і для масштабованих сервісів.
3. Чим Python відрізняється від компільованих мов програмування?
#### Python
Python зазвичай виконується інтерпретатором: код компілюється у байткод і
виконується в рантаймі (CPython VM). У компільованих мовах (C/C++, Rust)
переважно є попередня компіляція у машинний код.
Практичні наслідки:
- Python швидше в розробці та прототипуванні.
- Нативні компільовані мови зазвичай швидші у CPU-bound задачах.
- У Python продуктивність часто покращують алгоритмами, профілюванням і
C-розширеннями.
**Коротко:**
- Python оптимізує швидкість розробки.
- Компіляція в машинний код зазвичай дає кращу raw-продуктивність.
- Вибір залежить від домену та вимог до latency/throughput.
4. Що означає динамічна типізація в Python?
#### Python
Динамічна типізація означає, що тип прив'язаний до об'єкта, а не до імені
змінної. Ім'я може посилатися на значення різних типів у різний час виконання.
```python
value = 10 # int
value = "10" # str
```
Типи перевіряються під час виконання, тому помилки типів виникають у runtime,
якщо не використовувати статичний аналізатор типів.
**Коротко:**
- У Python тип має об'єкт, не змінна.
- Тип може змінюватися при перевизначенні імені.
- Type hints додають контроль до запуску коду.
5. Що означає строгість типів (strong typing) у Python?
#### Python
Strong typing у Python означає, що інтерпретатор не виконує небезпечні неявні
перетворення між несумісними типами.
```python
1 + "2" # TypeError
```
Для операцій між різними типами потрібне явне приведення:
```python
1 + int("2") # 3
```
**Коротко:**
- Python динамічно типізований, але строгий щодо сумісності типів.
- Небезпечні неявні конверсії блокуються помилкою.
- Явне приведення робить поведінку передбачуваною.
6. Що таке REPL і коли його використовують?
#### Python
REPL (Read-Eval-Print Loop) це інтерактивний режим, де ви вводите вираз,
отримуєте результат одразу і швидко перевіряєте гіпотези.
Застосування:
- перевірити API бібліотеки;
- швидко протестувати вираз або алгоритм;
- дослідити дані перед імплементацією в модулі.
Інструменти: стандартний `python`, `ipython`, `ptpython`.
**Коротко:**
- REPL дає найшвидший фідбек-цикл.
- Зручний для експериментів і дебагу.
- Не замінює тести, але скорочує час перевірки ідей.
7. Що таке literals у Python, наведіть приклади різних типів literals?
#### Python
Literal це фіксоване значення, записане прямо в коді.
```python
name = "Ada" # str literal
count = 42 # int literal
ratio = 3.14 # float literal
enabled = True # bool literal
items = [1, 2, 3] # list literal
config = {"retries": 3} # dict literal
flags = {"a", "b"} # set literal
point = (10, 20) # tuple literal
raw = b"abc" # bytes literal
```
**Коротко:**
- Literals це вбудовані константні значення в коді.
- Кожен базовий тип має свій синтаксис літерала.
- Вони часто використовуються для ініціалізації даних.
8. Що таке keywords у Python?
#### Python
Keywords це зарезервовані слова мови, які мають спеціальне синтаксичне
призначення і не можуть бути іменами змінних.
Приклади: `if`, `for`, `class`, `def`, `match`, `case`, `try`, `except`,
`async`, `await`.
Переглянути список:
```python
import keyword
print(keyword.kwlist)
```
**Коротко:**
- Keywords формують синтаксис Python.
- Їх не можна використовувати як ідентифікатори.
- Список доступний через модуль `keyword`.
9. Що таке змінна в Python?
#### Python
Змінна в Python це ім'я (reference), яке посилається на об'єкт у пам'яті.
Присвоєння зв'язує ім'я з об'єктом, а не "кладе значення в коробку".
```python
x = [1, 2]
y = x
y.append(3)
# x і y посилаються на один список
```
**Коротко:**
- Змінна це посилання на об'єкт.
- Кілька імен можуть посилатися на один mutable-об'єкт.
- Це важливо для розуміння копіювання і побічних ефектів.
10. Що таке `pass` і `...` (Ellipsis) у Python?
#### Python
`pass` це оператор-заглушка: нічого не робить, але дозволяє синтаксично
коректний порожній блок.
`...` (Ellipsis) це окремий об'єкт `Ellipsis`. Часто використовується як маркер
"ще не реалізовано", у type hints та бібліотеках (наприклад NumPy).
```python
def feature() -> None:
pass
PLACEHOLDER = ...
```
**Коротко:**
- `pass` потрібен для порожніх блоків коду.
- `...` це значення-об'єкт, а не ключове слово.
- Обидва використовують як тимчасові заглушки з різною семантикою.
11. Що таке PEP і як він впливає на розвиток Python?
#### Python
PEP (Python Enhancement Proposal) це офіційний документ, який описує нову фічу,
стандарт або процес у екосистемі Python.
Через PEP проходять:
- обговорення дизайну;
- технічна аргументація;
- рішення про прийняття/відхилення;
- стандартизація практик.
Приклади: PEP 8 (style), PEP 484 (type hints), PEP 634 (pattern matching).
**Коротко:**
- PEP це механізм еволюції мови та інструментів.
- Він робить зміни прозорими й формалізованими.
- Багато сучасних практик Python закріплені саме через PEP.
12. Що таке PEP 8 і навіщо він потрібен?
#### Python
PEP 8 це офіційний стиль-гайд для Python-коду: іменування, форматування,
відступи, імпорти, довжина рядків, читабельність конструкцій.
Навіщо потрібен:
- код має однаковий стиль у команді;
- швидше code review;
- менше шуму в diff;
- вища підтримуваність.
На практиці стиль автоматизують через `ruff format` або `black` + `ruff`.
**Коротко:**
- PEP 8 стандартизує стиль Python-коду.
- Це про читабельність і підтримку, не про продуктивність.
- Дотримання краще автоматизувати інструментами.
13. Які нові можливості з'явилися у сучасних версіях Python (3.10+)?
#### Python
Ключові можливості сучасного Python:
- `match/case` (structural pattern matching);
- покращений синтаксис і повідомлення про помилки;
- union-типи через `|` (`int | None`);
- `typing.Self`, `typing.TypeAlias`, `typing.override`;
- generics у стилі PEP 695 (`class Box[T]: ...`, `def f[T](...) -> ...`);
- `tomllib` у стандартній бібліотеці.
Практично це зменшує boilerplate і покращує надійність типізованого коду.
**Коротко:**
- Python 3.10+ суттєво покращив синтаксис і typing.
- `match/case` і сучасний `typing` найпомітніше впливають на код.
- Нові фічі варто використовувати в новому коді за замовчуванням.
14. Що таке docstring у Python?
#### Python
Docstring це рядок документації, перший вираз у модулі, класі або функції. Він
доступний через `__doc__` і використовується IDE, `help()`, генераторами docs.
```python
def normalize_email(email: str) -> str:
"""Return lowercase email without surrounding spaces."""
return email.strip().lower()
```
Рекомендовано описувати: що робить функція, аргументи, повернення, винятки.
**Коротко:**
- Docstring це вбудована документація в коді.
- Працює як джерело для `help()` та автогенерації docs.
- Якісний docstring зменшує потребу читати реалізацію.
15. Як працюють відступи (indentation) у Python?
#### Python
У Python відступи визначають блоки коду (тіло `if`, `for`, `def`, `class`).
Тобто відступ є частиною синтаксису, а не лише стилем.
```python
if is_ready:
run_task()
else:
stop_task()
```
Змішування tab і spaces може призвести до `IndentationError` або некоректної
структури блоку.
**Коротко:**
- Відступ у Python задає структуру програми.
- Неправильний відступ ламає виконання.
- Використовуйте стабільний стиль (4 пробіли).
16. Скільки пробілів потрібно для відступу відповідно до PEP8 та чому важливо дотримуватись однакового відступу?
#### Python
PEP 8 рекомендує **4 пробіли** на один рівень відступу.
Чому це критично:
- однакова структура блоку в усьому проєкті;
- передбачуваний вигляд у різних редакторах;
- менше помилок через tab/space конфлікти;
- чистіший diff у Git.
**Коротко:**
- Стандартний відступ: 4 пробіли.
- Єдиний стиль прибирає клас помилок форматування.
- Це напряму покращує читабельність і підтримку коду.
17. У чому різниця між `ruff` і `black` щодо функціоналу та використання?
#### Python
`black` це форматер коду з фіксованими правилами.
`ruff` це швидкий linter, а також форматер і автофіксер багатьох правил (PEP8,
імпорти, потенційні баги, спрощення синтаксису).
Практичні підходи:
- або `ruff check --fix` + `ruff format`;
- або `ruff` для lint + `black` для форматування.
**Коротко:**
- `black` фокусується на форматуванні.
- `ruff` закриває linting і частину автоправок.
- У сучасних проєктах часто достатньо одного `ruff`.
18. Поясніть призначення type annotations у Python і наведіть приклад функції з type annotations.
#### Python
Type annotations описують очікувані типи аргументів і повернення. Вони
покращують автодоповнення, статичний аналіз і читабельність API.
```python
def process_users(users: list[dict[str, object]]) -> list[str]:
return [str(user["name"]) for user in users if bool(user.get("active"))]
```
Анотації не виконують runtime-валідацію самі по собі, але допомагають знайти
помилки на етапі CI через `mypy`/`pyright`.
**Коротко:**
- Type hints документують контракт функції.
- Дають раннє виявлення помилок через static checking.
- Підвищують якість API у великих кодових базах.
19. Що таке debugging і чому це важливий навик для програмістів?
#### Python
Debugging це системний пошук причини некоректної поведінки коду та її усунення.
Це не лише "знайти баг", а відтворити, локалізувати і перевірити fix.
Базовий цикл:
- відтворити проблему;
- звузити ділянку коду;
- перевірити гіпотезу (логами/дебагером);
- додати тест, що фіксує сценарій.
**Коротко:**
- Debugging зменшує MTTR і кількість регресій.
- Працює найкраще як процес, а не хаотичний пошук.
- Завершення дебагу: fix + тест + постперевірка.
20. Поясніть призначення використання функції `print` для налагодження. Наведіть приклад ситуації, коли цей підхід корисний.
#### Python
`print`-debugging це швидкий спосіб перевірити значення змінних і порядок
виконання без запуску складних інструментів.
Корисно, коли треба швидко перевірити гіпотезу в локальному скрипті:
```python
def parse_port(raw: str) -> int:
value = raw.strip()
print(f"raw={raw!r} value={value!r}")
return int(value)
```
Для продакшен-коду краще переходити на `logging`, щоб мати рівні логів і
кероване виведення.
**Коротко:**
- `print` підходить для короткої локальної діагностики.
- Швидко показує стан змінних у проблемній точці.
- Для стабільної діагностики в сервісі використовуйте `logging`.
21. Опишіть, як можна використовувати Python Debugger (PDB) для налагодження. Які переваги PDB у порівнянні з `print`?
#### Python
`pdb` дозволяє зупиняти виконання програми, крокувати по рядках, дивитися стан
змінних і стек викликів.
Базове використання:
```python
import pdb
def compute(x: int) -> int:
pdb.set_trace()
return x * 2
```
Ключові команди: `n` (next), `s` (step), `c` (continue), `p expr` (print expr),
`l` (list), `bt` (backtrace).
**Коротко:**
- `pdb` дає інтерактивний контроль виконання.
- Ефективніший за `print` для складних сценаріїв.
- Дозволяє діагностувати стан без засмічення коду логами.
22. Які стратегії можна застосовувати для налагодження циклів та функцій у Python?
#### Python
Практичні стратегії:
- локалізувати баг через мінімальний відтворюваний приклад;
- логувати інваріанти на ітераціях циклу;
- ставити breakpoint на вхід/вихід функції;
- перевіряти крайні випадки (порожні дані, `None`, великі обсяги);
- покривати проблемний шлях тестом.
Для циклів корисно логувати індекс і ключові проміжні стани.
**Коротко:**
- Починайте з відтворення і звуження проблеми.
- Перевіряйте інваріанти і крайні умови.
- Фіналізуйте фікс тестом, що ловить регресію.
23. Який вплив мають довготривалі функції на продуктивність програми?
#### Python
Довготривалі функції збільшують latency, блокують воркери/потоки і погіршують
пропускну здатність сервісу.
Ризики:
- повільні відповіді API;
- таймаути;
- зростання черг задач;
- гірше використання CPU/IO.
Підхід: профілювати (`cProfile`), розбивати на менші кроки, використовувати
генератори/стрімінг, виносити важкі обчислення в `multiprocessing` або фон.
**Коротко:**
- Довгі функції напряму б'ють по latency.
- Оптимізацію роблять на основі профілювання, не інтуїції.
- Архітектурно краще розділяти CPU-bound і IO-bound роботу.
24. Що таке logging і чому його краще використовувати замість `print`?
#### Python
`logging` це стандартний механізм журналювання подій із рівнями (`DEBUG`,
`INFO`, `WARNING`, `ERROR`, `CRITICAL`), форматами й обробниками (console,
file).
Чому краще за `print`:
- керовані рівні деталізації;
- структурований формат;
- централізована конфігурація;
- можливість інтеграції з observability-стеком.
**Коротко:**
- `logging` придатний для продакшену, `print` ні.
- Рівні логів дають контроль шуму.
- Логи мають бути структурованими й консистентними.
25. Що таке traceback?
#### Python
Traceback це стек викликів, який Python показує при винятку: де почалось
виконання, через які функції пройшов код і де саме сталася помилка.
Використання:
- швидко знайти файл/рядок джерела помилки;
- зрозуміти шлях виконання до збою;
- побудувати точний тест на відтворення.
**Коротко:**
- Traceback це "маршрут" до помилки.
- Найцінніша частина: останні кадри стека і тип винятку.
- Аналіз traceback прискорює root-cause.
26. Які основні типи даних існують у Python?
#### Python
Основні built-in типи:
- числові: `int`, `float`, `complex`;
- логічний: `bool`;
- рядки/байти: `str`, `bytes`, `bytearray`;
- колекції: `list`, `tuple`, `set`, `dict`, `frozenset`;
- спеціальні: `NoneType` (`None`).
Важливо розуміти mutability:
- mutable: `list`, `dict`, `set`, `bytearray`;
- immutable: `int`, `str`, `tuple`, `frozenset`.
**Коротко:**
- Python має багатий набір базових типів "з коробки".
- Вибір структури даних впливає на складність операцій.
- Mutability визначає поведінку копіювання та побічні ефекти.
27. Яка різниця між звичайним діленням (`/`) і цілочисельним діленням (`//`) у Python?
#### Python
`/` виконує звичайне ділення і завжди повертає `float`.
`//` виконує floor-ділення: повертає цілу частину вниз (до `-∞`), тип зазвичай
`int` для цілих операндів.
```python
7 / 2 # 3.5
7 // 2 # 3
-7 // 2 # -4
```
**Коротко:**
- `/` -> дійсний результат.
- `//` -> округлення вниз до цілого.
- Для від'ємних чисел `//` не еквівалентне "обрізанню до нуля".
28. Поясніть використання оператора модуля (`%`) у Python. Як його можна використати щоб визначити, чи число парне або непарне?
#### Python
Оператор `%` повертає остачу від ділення.
Перевірка парності:
```python
def is_even(n: int) -> bool:
return n % 2 == 0
```
Якщо `n % 2 == 0`, число парне; інакше непарне.
Типові задачі: циклічні індекси, розбиття на групи, календарні обчислення.
**Коротко:**
- `%` повертає remainder.
- `n % 2` це стандартна перевірка парності.
- Часто використовується для циклічної логіки.
29. Як Python працює з великими цілими числами і які є обмеження при роботі з дуже великими числами?
#### Python
`int` у Python має довільну точність (arbitrary precision), тобто не обмежений
32/64-бітами як у багатьох мовах.
Обмеження практичні:
- пам'ять процесу;
- час обчислень на дуже великих значеннях;
- вартість операцій зростає зі збільшенням кількості цифр.
**Коротко:**
- Переповнення `int` у звичному сенсі немає.
- Обмеження: ресурси машини, а не фіксований бітовий розмір.
- Для великих обчислень важливі алгоритми і профілювання.
30. Яке значення має обробка ділення на нуль у Python, як запобігти `ZeroDivisionError` у коді?
#### Python
Ділення на нуль викликає `ZeroDivisionError`. Це треба обробляти явно, якщо
дільник надходить із зовнішнього вводу або розраховується динамічно.
```python
def safe_div(a: float, b: float) -> float | None:
if b == 0:
return None
return a / b
```
У критичних сценаріях використовуйте `try/except` і логування контексту.
**Коротко:**
- Ділення на нуль це контрольована runtime-помилка.
- Найпростіше запобігання: перевірка дільника до операції.
- Для зовнішніх даних додавайте захист і діагностику.
31. Опишіть використання модуля `random` у Python. Які найбільш поширені функції у цьому модулі?
#### Python
`random` використовується для псевдовипадкових значень у симуляціях, тестових
даних, non-crypto задачах.
Поширені функції:
- `random()` — число у `[0.0, 1.0)`;
- `randint(a, b)` — ціле в діапазоні;
- `randrange(start, stop, step)` — як range, але випадковий елемент;
- `choice(seq)` / `choices(seq, k=...)`;
- `shuffle(list_)` — перемішує список in-place;
- `sample(population, k)` — унікальна вибірка.
Для криптографії використовуйте `secrets`, не `random`.
**Коротко:**
- `random` підходить для звичайної прикладної випадковості.
- Найчастіше: `randint`, `choice`, `shuffle`, `sample`.
- Для security-sensitive задач потрібен `secrets`.
32. Як у Python працювати з числами з кращою точністю?
#### Python
Для фінансових і точних десяткових обчислень використовуйте `decimal.Decimal`, а
не `float`.
```python
from decimal import Decimal
total = Decimal("0.1") + Decimal("0.2") # Decimal('0.3')
```
Для раціональних чисел корисний `fractions.Fraction`.
**Коротко:**
- `float` зручний, але має похибки двійкового представлення.
- Для точної десяткової арифметики обирайте `Decimal`.
- Тип числа має відповідати домену задачі.
33. Що таке escape-символи у рядках Python і як їх використовують? Наведіть приклади для `\n`, `\t`, `\r`, `\"`, і `\'`.
#### Python
Escape-послідовності це спеціальні комбінації з `\`, які кодують службові
символи всередині рядка.
- `\n` — новий рядок
- `\t` — табуляція
- `\r` — повернення каретки
- `\"` — подвійна лапка в рядку з `"`
- `\'` — одинарна лапка в рядку з `'`
```python
text = "A\tB\n\"quoted\"\nI\'m here\rX"
```
**Коротко:**
- Escape-символи керують форматуванням рядка.
- Дозволяють вставляти лапки без ламання синтаксису.
- Для шляхів/regex часто зручно використовувати raw-рядки `r"..."`.
34. Поясніть використання методів `strip`, `lstrip` та `rstrip` у Python. Чим вони відрізняються?
#### Python
Методи працюють з краями рядка:
- `strip()` — прибирає символи з обох боків;
- `lstrip()` — лише зліва;
- `rstrip()` — лише справа.
За замовчуванням видаляють whitespace, або конкретний набір символів:
```python
" hello ".strip() # "hello"
"--id--".strip("-") # "id"
```
**Коротко:**
- `strip`-сімейство не змінює рядок in-place, а повертає новий.
- Різниця лише у стороні очищення.
- Часто використовується на вхідних даних.
35. Опишіть призначення методу `count` у рядках. Як він працює?
#### Python
`str.count(sub[, start[, end]])` рахує кількість неперекривних входжень підрядка
`sub` у вибраному діапазоні.
```python
"banana".count("an") # 2
"banana".count("a", 2) # 2
```
Повертає `0`, якщо входжень немає.
**Коротко:**
- `count` швидко дає кількість входжень підрядка.
- Підтримує обмеження пошуку через `start/end`.
- Рахує неперекривні входження.
36. Як працює метод `join` у Python і для чого найчастіше його використовують?
#### Python
`sep.join(iterable)` з'єднує послідовність рядків в один рядок через розділювач
`sep`.
```python
names = ["Ada", "Linus", "Guido"]
result = ", ".join(names) # "Ada, Linus, Guido"
```
Типове застосування: формування CSV-подібних рядків, логів, SQL-фрагментів,
URL-шляхів, повідомлень.
**Коротко:**
- `join` це стандартний і швидкий спосіб склеювання рядків.
- Викликається на розділювачі, не на списку.
- Ефективніший за багаторазове `+=` у циклі.
37. Що таке slicing (нарізка) у Python і як з її допомогою отримати підрядки? Наведіть приклади з позитивними та негативними індексами.
#### Python
Slicing це вибір частини послідовності через `[start:stop:step]`.
```python
s = "python"
s[1:4] # "yth"
s[:2] # "py"
s[-3:] # "hon"
s[::-1] # "nohtyp"
```
`start` включається, `stop` не включається.
**Коротко:**
- Slicing працює для рядків, списків, кортежів.
- Негативні індекси рахуються з кінця.
- Це базовий інструмент обробки послідовностей без циклів.
38. Поясніть метод `replace` для рядків. Як ним можна замінити декілька входжень підрядка?
#### Python
`str.replace(old, new, count=-1)` повертає новий рядок, де `old` замінено на
`new`. За замовчуванням замінюються всі входження.
```python
"foo bar foo".replace("foo", "baz") # "baz bar baz"
"foo bar foo".replace("foo", "baz", 1) # "baz bar foo"
```
**Коротко:**
- `replace` не змінює рядок in-place.
- Без `count` замінює всі входження.
- `count` дозволяє контролювати кількість замін.
39. Як працює метод `split` у рядках?
#### Python
`split(sep=None, maxsplit=-1)` ділить рядок на список підрядків.
- без `sep` ділить по будь-яких пробільних символах;
- з `sep` ділить по конкретному розділювачу;
- `maxsplit` обмежує кількість розділень.
```python
"a,b,c".split(",") # ["a", "b", "c"]
"a b c".split() # ["a", "b", "c"]
"k=v=x".split("=", 1) # ["k", "v=x"]
```
**Коротко:**
- `split` перетворює рядок у список токенів.
- `sep=None` має спеціальну поведінку для whitespace.
- `maxsplit` корисний для парсингу key/value форматів.
40. Як працює приведення типів (type casting)?
#### Python
Type casting це явне перетворення значення між типами через конструктори:
`int()`, `float()`, `str()`, `bool()`, `list()`, `tuple()`, `set()`, `dict()`.
```python
age = int("42")
price = float("19.99")
text = str(10)
```
Некоректні дані спричиняють виняток (`ValueError`, `TypeError`), тому для
зовнішнього вводу потрібна валідація.
**Коротко:**
- Python надає явні функції конверсії типів.
- Не всі значення можна безпечно конвертувати.
- Для user input потрібні перевірки й обробка винятків.
41. Як Python автоматично конвертує різні типи даних у значення boolean?
#### Python
У булевому контексті Python застосовує truthiness правила.
`False`-подібні значення:
- `False`, `None`;
- нульові числа: `0`, `0.0`, `0j`;
- порожні колекції: `""`, `[]`, `{}`, `set()`, `tuple()`, `range(0)`.
Усе інше зазвичай `True`.
```python
bool([]) # False
bool("0") # True
```
**Коротко:**
- Boolean-конверсія базується на truthy/falsy правилах.
- Порожнє і нульове -> `False`.
- Непорожній рядок `"0"` все одно `True`.
42. Поясніть, як перетворити рядок у ціле або дійсне число у Python. Що буде, якщо рядок не можна перетворити у число?
#### Python
Для перетворення використовуйте `int()` і `float()`:
```python
count = int("42")
ratio = float("3.14")
```
Якщо рядок невалідний, Python піднімає `ValueError`.
```python
def parse_int(value: str) -> int | None:
try:
return int(value)
except ValueError:
return None
```
**Коротко:**
- `int()`/`float()` виконують явну конверсію з рядка.
- Невалідний формат -> `ValueError`.
- Для зовнішніх даних потрібен `try/except`.
43. Що робить Python при порівнянні різних типів даних, таких як цілі числа і дійсні, або цілі числа і boolean?
#### Python
Python дозволяє числове порівняння сумісних numeric-типів.
- `int` і `float` порівнюються за значенням.
- `bool` є підкласом `int`: `False == 0`, `True == 1`.
```python
1 == 1.0 # True
True == 1 # True
False < 1 # True
```
Для несумісних типів (наприклад `int` і `str`) порівняння порядку (`<`, `>`)
викликає `TypeError`.
**Коротко:**
- `int`, `float`, `bool` мають спільну numeric-семантику.
- `bool` поводиться як `0/1` у порівняннях.
- Несумісні типи не порівнюються оператором порядку.
44. Як Python обробляє порівняння між списками та set?
#### Python
`list` і `set` це різні типи з різною семантикою, тому пряме порівняння порядку
між ними не підтримується.
```python
[1, 2] == {1, 2} # False
[1, 2] < {1, 2} # TypeError
```
Якщо треба порівняти склад елементів, нормалізуйте тип:
```python
set([1, 2]) == {1, 2} # True
```
**Коротко:**
- `list` і `set` порівнюються як різні структури даних.
- `==` між ними зазвичай `False`.
- Для змістовного порівняння спершу приводьте до одного типу.
45. Опишіть використання функції `bool()` у Python.
#### Python
`bool(x)` повертає булеве значення `x` за правилами truthiness.
Типові сценарії:
- явне перетворення значення до `True/False`;
- читабельні умови;
- побудова фільтрів.
```python
bool("text") # True
bool("") # False
bool(0) # False
```
**Коротко:**
- `bool()` уніфікує перевірку "порожнє/непорожнє".
- Спирається на вбудовані правила truthy/falsy.
- Корисний для валідації та умовної логіки.
46. У чому різниця між `list` і `tuple`?
#### Python
Головна різниця: `list` mutable, `tuple` immutable.
Практичні наслідки:
- `list` підходить для даних, що змінюються;
- `tuple` підходить для фіксованих записів;
- `tuple` можна використовувати як ключ словника (якщо елементи хешовані).
```python
coords: tuple[float, float] = (50.45, 30.52)
queue: list[str] = ["task-1", "task-2"]
```
**Коротко:**
- `list` для змінних колекцій.
- `tuple` для незмінних структур даних.
- Вибір впливає на безпечність API і використання в `dict/set`.
47. Як можна створити `tuple`?
#### Python
Основні способи:
```python
t1 = (1, 2, 3)
t2 = 1, 2, 3
t3 = tuple([1, 2, 3])
single = (42,) # важлива кома
empty = ()
```
Для одного елемента кома обов'язкова, інакше це просто вираз у дужках.
**Коротко:**
- `tuple` створюють через літерал або `tuple(iterable)`.
- `single = (x,)` це коректний одноелементний tuple.
- Порожній tuple: `()`.
48. Яка різниця між методом `reverse` і нарізкою `[::-1]` при перевертанні списку?
#### Python
`list.reverse()` змінює існуючий список in-place і повертає `None`.
`lst[::-1]` створює новий перевернутий список (копію).
```python
values = [1, 2, 3]
values.reverse() # values -> [3, 2, 1]
other = values[::-1] # новий список
```
**Коротко:**
- `reverse()` змінює оригінал.
- `[::-1]` повертає новий об'єкт.
- Вибір залежить від потреби зберегти вихідні дані.
49. Поясніть призначення та використання методу `sort` для списків. Як відсортувати список у спадному порядку?
#### Python
`list.sort()` сортує список in-place. Підтримує параметри:
- `key` — функція ключа сортування;
- `reverse=True` — спадний порядок.
```python
nums = [5, 1, 7]
nums.sort(reverse=True) # [7, 5, 1]
```
Якщо потрібна нова відсортована копія, використовуйте `sorted(iterable)`.
**Коротко:**
- `sort()` змінює список на місці.
- Для спадання використовуйте `reverse=True`.
- `sorted()` зручний, коли оригінал треба зберегти.
50. У чому різниця між методом `copy` і прямим присвоєнням одного списку іншому? Чому іноді важливо використовувати `copy`?
#### Python
Присвоєння копіює лише посилання:
```python
a = [1, 2]
b = a
b.append(3) # a теж зміниться
```
`a.copy()` створює новий (поверхневий) список:
```python
a = [1, 2]
b = a.copy()
b.append(3) # a не зміниться
```
Для вкладених структур може знадобитися `copy.deepcopy`.
**Коротко:**
- `=` не копіює дані, а ділить один об'єкт між змінними.
- `copy()` ізолює зміни на рівні верхнього списку.
- Для вкладених об'єктів використовуйте `deepcopy`.
51. Що робить метод `pop` у списку? Чим його поведінка відрізняється якщо вказати індекс і якщо ні?
#### Python
`pop()` видаляє і повертає елемент зі списку.
- `pop()` без аргументів видаляє останній елемент;
- `pop(i)` видаляє елемент за індексом `i`.
```python
items = ["a", "b", "c"]
last = items.pop() # "c"
first = items.pop(0) # "a"
```
Некоректний індекс викликає `IndexError`.
**Коротко:**
- `pop` поєднує видалення і повернення значення.
- Без індексу працює з кінцем списку.
- З індексом видаляє конкретну позицію.
52. Як об'єднати два списки у Python використовуючи оператор `+` і метод `extend`? У чому ключова різниця між цими двома способами?
#### Python
`a + b` створює **новий** список, а `a.extend(b)` змінює список `a`
**in-place**.
```python
a = [1, 2]
b = [3, 4]
c = a + b # [1, 2, 3, 4], a не змінився
a.extend(b) # a -> [1, 2, 3, 4]
```
**Коротко:**
- `+` повертає новий об'єкт.
- `extend()` мутує існуючий список.
- Вибір залежить від того, чи треба зберегти оригінал.
53. Для чого застосовуються функції `min`, `max`, `sum`, `all`, `any` у контексті списків?
#### Python
Це базові агрегатори для ітерованих колекцій:
- `min()` / `max()` — мінімум і максимум;
- `sum()` — сума чисел;
- `all()` — `True`, якщо всі елементи truthy;
- `any()` — `True`, якщо хоча б один елемент truthy.
```python
nums = [3, 10, 1]
min(nums), max(nums), sum(nums) # (1, 10, 14)
all([True, 1, "x"]) # True
any([0, "", None, 5]) # True
```
**Коротко:**
- Функції зменшують boilerplate у циклах.
- Працюють з будь-яким iterable.
- Добре поєднуються з генераторами для lazy-обробки.
54. Що таке словник (`dict`) у Python і чим він відрізняється від інших структур даних?
#### Python
`dict` це асоціативний масив: зберігає пари `ключ -> значення`. Ключі мають бути
hashable, значення можуть бути будь-якого типу.
Відмінності:
- доступ за ключем, а не за індексом;
- середня складність пошуку/вставки/видалення близька до `O(1)`;
- з Python 3.7+ зберігає порядок вставки ключів.
**Коротко:**
- `dict` оптимальний для швидкого доступу за ключем.
- Це основна структура для конфігурацій і мапінгів.
- Ключі повинні бути незмінними (hashable).
55. У чому різниця між отриманням значення зі словника через квадратні дужки `[]` і методом `get`?
#### Python
`d[key]` повертає значення або кидає `KeyError`, якщо ключа немає.
`d.get(key, default)` повертає значення або `default` (або `None`), без винятку.
```python
config = {"timeout": 30}
config["timeout"] # 30
config.get("retries", 3) # 3
```
**Коротко:**
- `[]` для обов'язкових ключів.
- `get()` для опціональних полів.
- `get()` зменшує кількість `try/except` у читанні даних.
56. Опишіть, як можна оновити та видалити елементи зі словника.
#### Python
Оновлення:
- `d[key] = value` — вставити/оновити один ключ;
- `d.update({...})` — масове оновлення.
Видалення:
- `del d[key]` — видалити ключ (помилка, якщо нема);
- `d.pop(key, default)` — видалити і повернути значення;
- `d.popitem()` — видалити останню пару;
- `d.clear()` — очистити весь словник.
**Коротко:**
- Для upsert підходять `[]` і `update()`.
- Для безпечного видалення частіше використовують `pop()`.
- Обирайте API залежно від бажаної поведінки при відсутньому ключі.
57. Для чого призначені методи `keys`, `values` та `items` у словниках?
#### Python
Ці методи повертають view-об'єкти словника:
- `keys()` — всі ключі;
- `values()` — всі значення;
- `items()` — пари `(key, value)`.
```python
data = {"a": 1, "b": 2}
for key, value in data.items():
...
```
View динамічні: відображають актуальний стан словника.
**Коротко:**
- `keys/values/items` потрібні для ітерації та перевірок.
- `items()` найзручніший для циклу з ключем і значенням.
- Це не копії, а "живі" представлення даних.
58. Як влаштований `dict` у Python під капотом?
#### Python
`dict` реалізований як hash table з оптимізаціями пам'яті і швидкого доступу.
Ключ хешується, за хешем обирається комірка, колізії розв'язуються внутрішнім
алгоритмом probing.
Практичні наслідки:
- середній доступ близько `O(1)`;
- якість `__hash__` і `__eq__` впливає на поведінку;
- mutable об'єкти не можна використовувати як ключі.
**Коротко:**
- `dict` це високопродуктивна hash-структура.
- Швидкість досягається за рахунок хешування.
- Ключі мають бути hashable та стабільними.
59. Що таке hash function?
#### Python
Hash function перетворює об'єкт у ціле число (hash), яке використовується для
швидкого розміщення/пошуку в `dict` і `set`.
Умови для коректності:
- якщо `a == b`, тоді `hash(a) == hash(b)`;
- значення хеша має бути стабільним протягом життя об'єкта.
**Коротко:**
- Хеш-функція є основою швидкої роботи `dict/set`.
- Вона не гарантує унікальність (можливі колізії).
- Для custom-класів важлива узгодженість `__eq__` і `__hash__`.
60. Що таке `set` у Python і чим він відрізняється від інших структур даних?
#### Python
`set` це невпорядкована колекція **унікальних** елементів.
Відмінності:
- автоматично прибирає дублікати;
- швидкі операції перевірки належності (`x in s`);
- підтримує теоретико-множинні операції: union/intersection/difference.
**Коротко:**
- `set` оптимальний для унікальності та membership-check.
- Порядок елементів не гарантується.
- Елементи мають бути hashable.
61. Як створити `set` у Python і які обмеження існують щодо елементів set?
#### Python
Створення:
```python
s1 = {1, 2, 3}
s2 = set([1, 2, 2, 3]) # {1, 2, 3}
empty = set() # не {}
```
Обмеження:
- елементи мають бути hashable (наприклад `int`, `str`, `tuple`);
- `list`, `dict`, `set` не можна додати напряму.
**Коротко:**
- `set()` створює порожню множину.
- Дублікати автоматично видаляються.
- Дозволені лише hashable-елементи.
62. Для чого використовується метод `intersection()` у Python set і чим він відрізняється від `union()`?
#### Python
`intersection()` повертає спільні елементи множин, а `union()` об'єднує всі
унікальні елементи з обох множин.
```python
a = {1, 2, 3}
b = {3, 4}
a.intersection(b) # {3}
a.union(b) # {1, 2, 3, 4}
```
**Коротко:**
- `intersection` = перетин (спільне).
- `union` = об'єднання (все унікальне).
- Обидва методи базові для порівняння наборів даних.
63. Які типи даних є immutable?
#### Python
Поширені immutable-типи:
- `int`, `float`, `bool`, `complex`;
- `str`, `bytes`;
- `tuple` (якщо елементи теж immutable);
- `frozenset`;
- `NoneType`.
**Коротко:**
- Immutable-об'єкт не можна змінити після створення.
- Замість мутації створюється новий об'єкт.
- Такі типи безпечніші для ключів `dict`/елементів `set`.
64. Які типи даних є mutable?
#### Python
Поширені mutable-типи:
- `list`;
- `dict`;
- `set`;
- `bytearray`;
- більшість user-defined об'єктів класів.
**Коротко:**
- Mutable-об'єкти змінюються in-place.
- Мутації можуть створювати побічні ефекти через спільні посилання.
- Потрібно обережно працювати з копіюванням.
65. Чому важливо розуміти змінюваність, працюючи зі словниками або set?
#### Python
`dict` і `set` базуються на хешуванні, тому їх елементи/ключі мають бути
стабільними (hashable). Mutable-об'єкти не можна безпечно використовувати як
ключі або елементи set.
Також мутація значень через спільні reference часто породжує неочікувані баги.
**Коротко:**
- Mutability впливає на коректність ключів у `dict/set`.
- Спільні mutable-об'єкти часто дають побічні ефекти.
- Явні копії і контроль мутацій зменшують баги.
66. Що таке `None`?
#### Python
`None` це спеціальне singleton-значення типу `NoneType`, яке означає
"відсутність значення".
Типові сценарії:
- функція нічого явно не повертає;
- опціональні параметри;
- маркер "дані ще не задані".
Перевірка виконується через `is`:
```python
if value is None:
...
```
**Коротко:**
- `None` означає відсутність значення.
- Це singleton, тому порівнюють через `is`.
- Часто використовується в API як опціональний стан.
67. Що таке `id` у Python, як його використовувати і чому це важливо?
#### Python
`id(obj)` повертає ідентифікатор об'єкта (унікальний в межах життєвого циклу
об'єкта в поточному процесі).
Корисно для діагностики:
- чи це той самий об'єкт;
- чи створено копію;
- чи сталася мутація спільного reference.
**Коротко:**
- `id` допомагає аналізувати identity об'єктів.
- Корисний у дебазі копіювання/мутацій.
- Не використовується як бізнес-ідентифікатор.
68. Яка різниця між операторами `is` та `==`?
#### Python
`==` порівнює **значення** (еквівалентність), а `is` порівнює **ідентичність**
(чи це один і той самий об'єкт у пам'яті).
```python
a = [1, 2]
b = [1, 2]
a == b # True
a is b # False
```
**Важливо про оптимізації (Interning):** CPython кешує ("інтернує") малі цілі
числа (від -5 до 256) та короткі рядки на етапі компіляції/завантаження. Тому
для них `is` може повертати `True`, навіть якщо вони створені окремо. Але це
деталі реалізації, на які не варто покладатися в бізнес-логіці.
Для `None` завжди використовуйте `is`.
**Коротко:**
- `==` про рівність значень.
- `is` про той самий об'єкт у пам'яті.
- Interning може давати неочевидний `is True` для малих `int` та `str`.
- `value is None` — це єдиний правильний стиль для перевірки на `None`.
69. Як застосовується Singleton pattern у Python? Наведіть приклади Singleton-об'єктів у Python.
#### Python
Singleton означає один глобальний екземпляр об'єкта в процесі. У Python його
часто замінюють модульним рівнем (модулі імпортуються один раз).
Приклади singleton-об'єктів мови:
- `None`;
- `True` і `False`;
- `Ellipsis`.
У прикладному коді замість жорсткого Singleton частіше використовують
DI-контейнер або фабрики для кращої тестованості.
**Коротко:**
- Python вже має вбудовані singleton-об'єкти.
- Часто достатньо модульного скоупу без окремого патерна.
- Зловживання Singleton погіршує тестованість.
70. Для чого використовуються оператори `break` та `continue` в циклах Python?
#### Python
`break` достроково завершує цикл, `continue` пропускає поточну ітерацію і
переходить до наступної.
```python
for n in range(10):
if n == 5:
break
if n % 2 == 0:
continue
```
**Коротко:**
- `break` зупиняє цикл повністю.
- `continue` пропускає лише поточний крок.
- Вони роблять керування циклом явним і читабельним.
71. Поясніть поняття нескінченного циклу. У яких випадках доречно використовувати нескінченний цикл і як забезпечити його коректне завершення?
#### Python
Нескінченний цикл це цикл без природної умови завершення, наприклад
`while True`. Використовується для daemon/worker-процесів, polling, event-loop
логіки.
Коректне завершення:
- чітка умова `break`;
- обробка сигналів завершення;
- таймаути й `try/finally` для clean-up.
```python
while True:
task = queue.get()
if task is None:
break
handle(task)
```
**Коротко:**
- `while True` доречний для довгоживучих сервісних циклів.
- Потрібен контрольований механізм зупинки.
- Завжди передбачайте вивільнення ресурсів.
72. Опишіть, як працюють вкладені цикли у Python. Які проблеми з продуктивністю можуть виникати при їх використанні і як їх уникати?
#### Python
Вкладений цикл це цикл усередині іншого циклу. Часто складність стає `O(n*m)`
або гірше, що критично на великих даних.
Оптимізації:
- замінювати пошук у списках на `set`/`dict`;
- виносити інваріанти за межі внутрішнього циклу;
- застосовувати генератори, `itertools`, векторизацію;
- профілювати "гарячі" ділянки.
**Коротко:**
- Вкладені цикли швидко множать вартість обчислень.
- Структури даних часто важливіші за мікрооптимізації.
- Профілювання показує, що саме треба оптимізувати.
73. Що таке structural pattern matching (`match`/`case`)?
#### Python
`match/case` (Python 3.10+) це механізм розбору структури даних за шаблонами.
Працює з літералами, типами, послідовностями, словниками та класами.
```python
def handle(message: dict[str, object]) -> str:
match message:
case {"type": "ping"}:
return "pong"
case {"type": "user", "id": int(user_id)}:
return f"user:{user_id}"
case _:
return "unknown"
```
**Коротко:**
- `match/case` читається краще для складного розгалуження.
- Дозволяє одночасно перевіряти форму і виймати дані.
- Особливо корисний для протоколів/подій і парсингу структур.
74. У яких випадках pattern matching кращий за `if`/`elif`?
#### Python
`match/case` кращий, коли потрібно:
- перевіряти багато взаємовиключних форм даних;
- розпаковувати вкладені структури;
- уникати довгих ланцюгів `if/elif`.
`if/elif` кращий для простих булевих умов і короткої логіки.
**Коротко:**
- Для структурних сценаріїв краще `match/case`.
- Для простих умов достатньо `if/elif`.
- Критерій вибору: читабельність і підтримка.
75. Що таке функція в Python?
#### Python
Функція це іменований callable-блок коду, який приймає аргументи, повертає
результат і дозволяє інкапсулювати логіку.
```python
def normalize_name(name: str) -> str:
return name.strip().title()
```
Функції підтримують default-значення, keyword-аргументи, `*args/**kwargs`,
анотації типів, декоратори.
**Коротко:**
- Функція це базова одиниця повторного використання коду.
- Вона формує чіткий контракт через параметри й return.
- Type hints роблять контракт явним.
76. Які існують типи аргументів функцій?
#### Python
У сучасному Python:
- positional-only (`/`);
- positional-or-keyword;
- keyword-only (`*`);
- variadic positional (`*args`);
- variadic keyword (`**kwargs`).
```python
def f(a, /, b, *, c, **kwargs):
...
```
**Коротко:**
- Python дає гнучкий контроль способу виклику функції.
- `/` і `*` формалізують API-контракт.
- `*args/**kwargs` корисні для розширюваних інтерфейсів.
77. Що таке позиційні та іменовані аргументи?
#### Python
Позиційні аргументи передаються за порядком, іменовані (`keyword`) за назвою
параметра.
```python
def connect(host: str, port: int) -> str:
return f"{host}:{port}"
connect("localhost", 5432) # позиційно
connect(host="localhost", port=5432) # іменовано
```
**Коротко:**
- Позиційні залежать від порядку параметрів.
- Іменовані підвищують читабельність виклику.
- Їх можна комбінувати з дотриманням правил сигнатури.
78. Що таке аргументи за замовчуванням і які з ними можуть бути проблеми?
#### Python
Default-аргументи підставляються, якщо значення не передано під час виклику.
Вони обчислюються **один раз** при визначенні функції.
Проблема: mutable default.
```python
def add_item(item: int, bucket: list[int] | None = None) -> list[int]:
if bucket is None:
bucket = []
bucket.append(item)
return bucket
```
**Коротко:**
- Defaults зручні для стабільних значень.
- Mutable default може накопичувати стан між викликами.
- Безпечний патерн: `None` + ініціалізація всередині.
79. Поясніть призначення та використання `*args` і `**kwargs` у функціях Python. Чим вони відрізняються?
#### Python
`*args` збирає додаткові позиційні аргументи в `tuple`. `**kwargs` збирає
додаткові іменовані аргументи в `dict`.
```python
def log_event(event: str, *args: object, **kwargs: object) -> None:
...
```
Використання: обгортки, адаптери API, декоратори, проксування параметрів.
**Коротко:**
- `*args` = додаткові позиційні.
- `**kwargs` = додаткові іменовані.
- Вони роблять функції гнучкими, але потребують чіткої валідації.
80. Як визначити функцію з type annotations у Python? Наведіть приклад і поясніть переваги цього підходу.
#### Python
Типи задаються в сигнатурі параметрів і return-значення.
```python
def process_users(users: list[dict[str, object]]) -> list[str]:
return [str(user["name"]) for user in users if bool(user.get("active"))]
```
Переваги:
- кращий DX (autocomplete, навігація);
- статична перевірка в CI;
- явний контракт для інших розробників.
**Коротко:**
- Анотації типів документують API.
- Вони зменшують ризик помилок інтеграції.
- Найбільша користь у середніх і великих кодових базах.
81. Що таке lambda-функції?
#### Python
`lambda` це анонімна одно-виразна функція. Зазвичай використовується для
коротких callbacks у `sorted`, `map`, `filter`.
```python
users = [{"name": "Ada"}, {"name": "Bob"}]
users_sorted = sorted(users, key=lambda u: u["name"])
```
Для складної логіки краще звичайна `def`-функція.
**Коротко:**
- `lambda` зручна для коротких локальних виразів.
- Обмежена одним виразом.
- Для читабельності складний код краще виносити в `def`.
82. Яка область видимості змінних у функції?
#### Python
Python використовує правило LEGB для пошуку імен:
- `L`ocal;
- `E`nclosing (зовнішні функції);
- `G`lobal (модуль);
- `B`uiltins.
Усередині функції присвоєння створює локальну змінну, якщо не оголошено `global`
або `nonlocal`.
**Коротко:**
- Scope визначає, де ім'я доступне і змінюване.
- LEGB пояснює порядок пошуку змінних.
- Неправильне розуміння scope часто дає `UnboundLocalError`.
83. Що таке локальні та глобальні змінні у Python?
#### Python
Локальні змінні живуть у тілі функції. Глобальні змінні визначені на рівні
модуля.
Для зміни глобальної з функції потрібен `global`, але це зазвичай варто уникати
через неявні залежності.
**Коротко:**
- Локальні безпечніші для підтримки й тестування.
- Глобальні спрощують доступ, але ускладнюють контроль стану.
- Краще передавати залежності параметрами.
84. Яка різниця між локальними і nonlocal-змінними у Python?
#### Python
`nonlocal` використовується у вкладеній функції для зміни змінної із найближчого
enclosing-scope (не глобального).
```python
from collections.abc import Callable
def counter() -> Callable:
value = 0
def inc() -> int:
nonlocal value
value += 1
return value
return inc
```
**Коротко:**
- Локальна змінна належить поточній функції.
- `nonlocal` змінює стан зовнішньої функції.
- Це ключовий механізм для closure зі станом.
85. Що таке unpacking у Python і як його застосовують при присвоєнні?
#### Python
Unpacking це розкладання елементів послідовності/структури в окремі змінні.
```python
x, y = (10, 20)
first, *middle, last = [1, 2, 3, 4]
```
Працює також зі словниками в `match/case`, викликах функцій і циклах.
**Коротко:**
- Unpacking робить код компактнішим і читабельнішим.
- Підтримує "зірочковий" збір решти значень.
- Часто використовується в парсингу структур даних.
86. Поясніть поняття packing значень у Python і наведіть приклади.
#### Python
Packing це збирання кількох значень в одну структуру (`tuple`, `list`, `dict`).
```python
point = 10, 20 # tuple packing
def collect(*args: int) -> tuple[int, ...]:
return args
```
`*args` і `**kwargs` це типовий приклад packing аргументів.
**Коротко:**
- Packing збирає багато значень в один контейнер.
- Найчастіше використовується в сигнатурах функцій.
- Добре поєднується з unpacking на стороні виклику.
87. Для чого використовують оператор `*` при packing та unpacking?
#### Python
`*` у параметрах функції пакує позиційні аргументи (`*args`), а у виклику
розпаковує iterable в позиційні аргументи.
```python
def add(a: int, b: int) -> int:
return a + b
nums = [2, 3]
add(*nums) # 5
```
Також `*` використовується у присвоєнні для захоплення "решти" елементів.
**Коротко:**
- `*` універсальний оператор для роботи з varargs.
- У сигнатурі пакує, у виклику розпаковує.
- Зменшує шаблонний код при передачі даних.
88. Що таке closure і яке його відношення до decorator-ів?
#### Python
Closure це внутрішня функція, яка "пам'ятає" змінні enclosing-scope навіть після
завершення зовнішньої функції.
Decorator зазвичай реалізують саме через closure: обгортка зберігає посилання на
оригінальну функцію і додаткові параметри.
**Коротко:**
- Closure це функція + захоплений контекст.
- Decorator часто є практичним застосуванням closure.
- Дає можливість додати поведінку без зміни тіла функції.
89. Що таке decorator у Python і як він працює?
#### Python
Decorator це callable, який приймає функцію/клас і повертає модифіковану версію
(обгортку).
```python
from functools import wraps
def log_calls(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
```
Застосування: логування, кешування, авторизація, ретраї, метрики.
**Коротко:**
- Decorator додає cross-cutting поведінку.
- Працює через обгортання callable.
- Дозволяє не дублювати технічну логіку в бізнес-коді.
90. Чи можна використовувати декілька decorator-ів для однієї функції?
#### Python
Так, можна стекувати кілька декораторів. Вони застосовуються знизу вгору
(ближчий до `def` виконується першим обгортанням).
```python
@decorator_a
@decorator_b
def handler() -> None:
...
```
Еквівалент: `handler = decorator_a(decorator_b(handler))`.
**Коротко:**
- Кілька декораторів допустимі і поширені.
- Порядок застосування має значення.
- Стек декораторів треба документувати для прозорості.
91. Опишіть можливу проблему з черговістю decorator-ів при їх застосуванні до функції.
#### Python
Неправильний порядок може змінити семантику: наприклад, кешування до перевірки
доступу може закешувати небажаний результат або обійти очікувану логіку.
Типові ризики:
- логування бачить вже змінені аргументи;
- ретраї обгортають не той виняток;
- кеш ставиться до/після валідації в неправильній точці.
**Коротко:**
- Порядок декораторів впливає на поведінку функції.
- Це часта причина прихованих багів.
- Для критичних ланцюжків потрібні тести на порядок виконання.
92. Чи можна створити decorator за допомогою класу?
#### Python
Так. Клас-декоратор реалізує `__call__`, щоб екземпляр поводився як функція.
```python
class CallCounter:
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
return self.func(*args, **kwargs)
```
**Коротко:**
- Decorator можна реалізувати не лише функцією, а й класом.
- Клас зручний, коли потрібен внутрішній стан.
- Ключовий механізм: `__call__`.
93. Як визначити decorator, що приймає параметри?
#### Python
Потрібна трирівнева структура: фабрика декоратора -> декоратор -> wrapper.
```python
from functools import wraps
def retry(times: int):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times - 1):
try:
return func(*args, **kwargs)
except Exception:
pass
return func(*args, **kwargs)
return wrapper
return decorator
```
**Коротко:**
- Параметризований декоратор це функція, що повертає декоратор.
- Часто використовують closure для збереження параметрів.
- Такий підхід зручний для конфігурованої поведінки.
94. Для чого використовують `functools.wraps` у decorator-функціях?
#### Python
`functools.wraps` копіює метадані оригінальної функції в wrapper: ім'я,
docstring, модуль, а також `__wrapped__`.
Це важливо для:
- коректного дебагу й логів;
- інтроспекції та документації;
- сумісності з інструментами, що читають сигнатуру.
**Коротко:**
- `wraps` зберігає "ідентичність" оригінальної функції.
- Без нього декоровані функції втрачають корисні метадані.
- Це best practice для всіх wrapper-декораторів.
95. Як працюють dict comprehension, list comprehension і set comprehension?
#### Python
Comprehension створює колекцію з виразу і циклу(ів), опційно з фільтром.
```python
squares = [x * x for x in range(6)]
mapping = {x: x * x for x in range(6)}
unique = {x % 3 for x in range(10)}
```
Формат:
- list: `[expr for x in it if cond]`
- set: `{expr for x in it if cond}`
- dict: `{k_expr: v_expr for x in it if cond}`
**Коротко:**
- Comprehension компактно виражає трансформацію даних.
- Працює для `list`, `set`, `dict`.
- Дає чистіший код, ніж ручне додавання в циклі.
96. Які переваги використання list comprehensions у порівнянні зі звичайними циклами?
#### Python
Переваги:
- коротший і декларативніший код;
- менше службових змінних;
- зазвичай трохи краща продуктивність у CPython;
- нижчий ризик забути `append`.
Недолік: для дуже складної логіки comprehension погіршує читабельність.
**Коротко:**
- List comprehension добре підходить для простих трансформацій.
- Часто швидший і чистіший за ручний цикл.
- Для складних гілок краще звичайний `for`.
97. Чи можете навести приклад вкладеної list comprehension?
#### Python
Приклад flatten матриці:
```python
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [item for row in matrix for item in row] # [1, 2, 3, 4, 5, 6]
```
Приклад з умовою:
```python
pairs = [(x, y) for x in range(3) for y in range(3) if x != y]
```
**Коротко:**
- Вкладена comprehension це кілька `for` в одному виразі.
- Порядок `for` відповідає вкладеним циклам.
- Використовуйте, коли вираз залишається читабельним.
98. Що швидше у Python: list comprehension або створення списку за допомогою циклу?
#### Python
У типових сценаріях list comprehension трохи швидший за цикл з `append`, бо має
оптимізований байткод і менше накладних операцій.
Важливо: реальний приріст залежить від тіла операції, тому для критичних ділянок
варто вимірювати (`timeit`, `pyperf`).
**Коротко:**
- Часто швидше: list comprehension.
- Різниця може бути невеликою.
- Для production-рішень орієнтуйтесь на вимірювання.
99. Що таке iterator у Python?
#### Python
Iterator це об'єкт, який повертає елементи послідовно і пам'ятає поточний стан.
Він реалізує протокол:
- `__iter__()` повертає себе;
- `__next__()` повертає наступний елемент або кидає `StopIteration`.
**Коротко:**
- Iterator дає поелементний доступ без повного завантаження даних.
- Це база для `for`, генераторів і lazy-обробки.
- Після вичерпання iterator не "перемотується" сам.
100. Як створити iterator з ітерованого об'єкта за допомогою функції `iter()`?
#### Python
Викликайте `iter(iterable)`, щоб отримати iterator.
```python
items = [10, 20, 30]
it = iter(items)
```
Після цього значення читаються через `next(it)`.
**Коротко:**
- `iter()` перетворює iterable на iterator.
- Це явний спосіб керувати ітерацією вручну.
- Використовується у низькорівневій обробці потоку даних.
101. Для чого призначена функція `next()` при роботі з iterator-ами?
#### Python
`next(iterator[, default])` повертає наступний елемент iterator. Коли елементи
закінчились, кидає `StopIteration` або повертає `default`, якщо його передано.
```python
it = iter([1, 2])
next(it) # 1
next(it) # 2
next(it, None) # None
```
**Коротко:**
- `next()` дає ручний контроль кроку ітерації.
- Без `default` кінець потоку -> `StopIteration`.
- З `default` зручно безпечно читати потік.
102. Чи можна взаємозамінно використовувати методи `__next__()` і `__iter__()` з функціями `next()` та `iter()`?
#### Python
Так, але з нюансом протоколу:
- `iter(obj)` викликає `obj.__iter__()`;
- `next(it)` викликає `it.__next__()`.
Тобто функції є стандартним інтерфейсом до dunder-методів і зазвичай
використовуються замість прямого виклику.
**Коротко:**
- `iter()` відповідає `__iter__()`.
- `next()` відповідає `__next__()`.
- У прикладному коді краще викликати вбудовані функції.
103. Яка роль `StopIteration` у проєктуванні iterator-ів і коли це зазвичай виникає?
#### Python
`StopIteration` сигналізує, що iterator вичерпано. `for`-цикл перехоплює його
автоматично і завершує ітерацію.
Зазвичай виникає:
- при виклику `next(it)` після останнього елемента;
- у custom-ітераторах, коли дані закінчились.
**Коротко:**
- `StopIteration` це штатний кінець потоку.
- Його не треба логувати як "помилку" в normal-flow.
- У власних iterator-ах його треба піднімати коректно.
104. Що таке generator і чим він відрізняється від iterator чи звичайної функції?
#### Python
Generator це спеціальний iterator, який створюється функцією з `yield`. Він
генерує значення по одному і зберігає внутрішній стан між викликами.
Відмінності:
- від звичайної функції: не завершується одним `return`, а "пауза/продовження";
- від ручного iterator: простіша реалізація без явного класу `__next__`.
**Коротко:**
- Generator це найзручніший спосіб lazy-ітерації.
- Дає менше коду, ніж custom iterator-клас.
- Особливо корисний для великих потоків даних.
105. Як створити generator-функцію?
#### Python
Потрібно визначити функцію з `yield`.
```python
def countdown(start: int):
current = start
while current > 0:
yield current
current -= 1
```
Виклик `countdown(3)` повертає generator-об'єкт, який можна ітерувати.
**Коротко:**
- Наявність `yield` робить функцію генератором.
- Generator повертає значення поетапно.
- Стан функції зберігається між ітераціями.
106. Як ключове слово `yield` забезпечує функціональність generator-ів і чому вони економлять пам'ять?
#### Python
`yield` повертає чергове значення і "заморожує" контекст функції (локальні
змінні, позицію виконання). Наступний `next()` відновлює виконання з цієї точки.
Економія пам'яті: дані не створюються повністю наперед, а обчислюються
on-demand.
**Коротко:**
- `yield` реалізує паузу/продовження виконання.
- Generator підтримує lazy evaluation.
- Це знижує memory footprint для великих наборів даних.
107. У чому різниця між `return` і `yield`?
#### Python
`return` завершує функцію і повертає одне фінальне значення. `yield` повертає
проміжне значення і зберігає стан для подальшого продовження.
У генераторі `return` означає кінець ітерації (`StopIteration`).
**Коротко:**
- `return` -> завершення функції.
- `yield` -> поетапна видача значень.
- `yield` використовується для потокової обробки.
108. Що таке Object-Oriented Programming (OOP) та його головні принципи у Python?
#### Python
OOP це підхід, де дані і поведінка об'єднані в об'єктах.
Ключові принципи:
- інкапсуляція;
- наслідування;
- поліморфізм;
- абстракція.
У Python OOP зазвичай поєднується з композицією і duck typing.
**Коротко:**
- OOP структурує домен через класи й об'єкти.
- Python підтримує OOP гнучко, без надмірного шаблонного коду.
- На практиці композиція часто краща за глибоке наслідування.
109. Що таке `class` у Python?
#### Python
`class` це шаблон (blueprint) для створення об'єктів з атрибутами та методами.
```python
class User:
def __init__(self, name: str) -> None:
self.name = name
```
Клас задає структуру і поведінку майбутніх екземплярів.
**Коротко:**
- Клас описує дані й операції над ними.
- На основі класу створюються об'єкти (instances).
- Це базова одиниця моделювання в OOP.
110. Як створити object у Python?
#### Python
Об'єкт створюється викликом класу:
```python
class User:
def __init__(self, name: str) -> None:
self.name = name
user = User("Ada")
```
Під час створення виконується `__init__` для ініціалізації стану.
**Коротко:**
- Object = екземпляр класу.
- Створення: `instance = ClassName(...)`.
- `__init__` налаштовує початкові атрибути.
111. Що таке об'єкти та атрибути?
#### Python
Об'єкт це конкретний екземпляр типу/класу. Атрибут це пов'язане з об'єктом
ім'я-значення (дані або метод).
```python
user.name # атрибут-дані
user.save() # атрибут-метод
```
**Коротко:**
- Об'єкт зберігає стан і поведінку.
- Атрибути описують цей стан/поведінку.
- Доступ до атрибутів: крапкова нотація.
112. Яку роль виконує метод `__init__()` у класі?
#### Python
`__init__` це ініціалізатор екземпляра: викликається після створення об'єкта і
заповнює початковий стан.
```python
class Account:
def __init__(self, owner: str, balance: float = 0.0) -> None:
self.owner = owner
self.balance = balance
```
**Коротко:**
- `__init__` задає стартові атрибути об'єкта.
- Працює як вхідна точка конфігурації instance.
- Не створює об'єкт, а лише ініціалізує його.
113. Для чого параметр `self` у методах класу Python?
#### Python
`self` це посилання на поточний екземпляр, через нього метод читає/змінює
інстанс-атрибути.
```python
def deposit(self, amount: float) -> None:
self.balance += amount
```
Ім'я `self` не зарезервоване синтаксично, але є загальноприйнятим стандартом.
**Коротко:**
- `self` зв'язує метод з конкретним об'єктом.
- Через `self` доступні інстанс-дані.
- Це обов'язковий перший параметр instance method.
114. Як визначати методи у класі?
#### Python
Методи визначаються як функції всередині `class`.
```python
class Calculator:
def add(self, a: int, b: int) -> int:
return a + b
```
Типові види: instance (`self`), class (`@classmethod`, `cls`), static
(`@staticmethod`, без `self/cls`).
**Коротко:**
- Метод це функція в тілі класу.
- Тип методу визначається декоратором і сигнатурою.
- Найчастіше використовується instance method.
115. Поясніть концепцію "все є об'єктом" у Python і наведіть приклади.
#### Python
У Python майже все є об'єктом: числа, рядки, функції, класи, модулі. Тому у
всього є тип, атрибути й поведінка.
```python
type(10) # <class 'int'>
type(len) # <class 'builtin_function_or_method'>
type(str) # <class 'type'>
```
**Коротко:**
- Єдина об'єктна модель спрощує мову.
- Функції й класи теж об'єкти першого класу.
- Це робить Python гнучким для метапрограмування.
116. Наведіть приклад класу з методами, які виконують обчислення на основі атрибутів.
#### Python
```python
class Rectangle:
def __init__(self, width: float, height: float) -> None:
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
```
**Коротко:**
- Методи можуть обчислювати значення з інстанс-атрибутів.
- Це інкапсулює доменну логіку в об'єкті.
- API класу стає самодокументованим.
117. Опишіть ситуацію, коли може знадобитися використання кількох класів у Python-програмі.
#### Python
Коли домен має кілька відповідальностей, їх розділяють по класах. Наприклад
e-commerce: `Order`, `OrderItem`, `PaymentService`, `InventoryService`.
Це дає:
- чіткий розподіл відповідальностей;
- слабше зв'язування;
- простішу заміну/тестування компонентів.
**Коротко:**
- Кілька класів потрібні для моделювання складного домену.
- Розподіл відповідальностей підвищує підтримуваність.
- Композиція класів зазвичай краща за "god object".
118. У чому різниця між instance method, class method і static method?
#### Python
- Instance method: має `self`, працює з конкретним екземпляром.
- Class method: має `cls`, працює з класом загалом.
- Static method: не має `self/cls`, це утилітарна функція в namespace класу.
**Коротко:**
- Instance -> логіка екземпляра.
- Class -> логіка класу/альтернативні конструктори.
- Static -> допоміжна логіка без доступу до стану.
119. Що таке `@classmethod` у Python і чим він відрізняється від звичайних методів?
#### Python
`@classmethod` передає першим аргументом клас (`cls`), а не екземпляр. Часто
використовується для factory-методів.
```python
class User:
def __init__(self, name: str) -> None:
self.name = name
@classmethod
def from_email(cls, email: str) -> User:
return cls(email.split("@")[0])
```
**Коротко:**
- `classmethod` працює на рівні класу.
- Зручний для альтернативних конструкторів.
- Не потребує вже створеного instance.
120. Що таке `@staticmethod` у класах Python і коли його доцільно застосовувати?
#### Python
`@staticmethod` визначає метод без автоматичного `self` або `cls`. Він логічно
належить класу, але не залежить від стану.
```python
class Math:
@staticmethod
def clamp(value: int, min_v: int, max_v: int) -> int:
return max(min_v, min(value, max_v))
```
**Коротко:**
- `staticmethod` це функція в namespace класу.
- Використовуйте для допоміжної логіки без доступу до атрибутів.
- Не підходить, якщо потрібен стан instance або class.
121. У чому різниця між `@classmethod` і `@staticmethod` у класах Python?
#### Python
Різниця у першому аргументі і рівні доступу:
- `@classmethod` отримує `cls` і може працювати з класовим станом;
- `@staticmethod` не отримує нічого автоматично.
`classmethod` частіше для фабрик/поліморфних конструкторів, `staticmethod` для
утиліт.
**Коротко:**
- `classmethod` знає про клас.
- `staticmethod` ізольований від класового/інстанс стану.
- Вибір залежить від потреби доступу до `cls`.
122. Що таке інстанс-атрибути у класах Python і чим вони відрізняються від класових атрибутів?
#### Python
Інстанс-атрибути належать конкретному об'єкту (`self.x`). Класові атрибути
належать класу і спільні для всіх екземплярів.
```python
class User:
role = "member" # class attribute
def __init__(self, name: str) -> None:
self.name = name # instance attribute
```
**Коротко:**
- Інстанс-атрибути зберігають індивідуальний стан.
- Класові атрибути зберігають спільну конфігурацію.
- Мутації class-атрибутів впливають на всі instance.
123. Що таке `__slots__` у Python?
#### Python
`__slots__` обмежує набір дозволених атрибутів у класі і може зменшити
споживання пам'яті, прибираючи `__dict__` для екземплярів.
```python
class Point:
__slots__ = ("x", "y")
def __init__(self, x: int, y: int) -> None:
self.x = x
self.y = y
```
**Нюанси використання:**
- **Економія пам'яті:** об'єкти займають значно менше місця, бо атрибути
зберігаються у фіксованому масиві, а не в хеш-таблиці `__dict__`.
- **Швидкість:** доступ до атрибутів у `__slots__` зазвичай трохи швидший.
- **Відсутність `__dict__`:** ви не зможете динамічно додавати нові атрибути,
яких немає у списку `__slots__` (якщо тільки не додати `"__dict__"` у сам
список).
- **Слабкі посилання:** якщо ви хочете використовувати `weakref`, потрібно явно
додати `"__weakref__"` у `__slots__`.
**Коротко:**
- `__slots__` корисний для мільйонів легковагових об'єктів (напр. вузли графа).
- Прибирає `__dict__` і `__weakref__` за замовчуванням.
- Зменшує гнучкість на користь продуктивності та контролю.
124. Що таке magic methods (dunder методи) у класах Python і чому їх називають "магічними"?
#### Python
Dunder-методи (`__init__`, `__str__`, `__len__`, `__eq__`, ...) це спеціальні
хуки, які Python викликає автоматично у відповідь на оператори та built-ins.
Їх називають "магічними", бо вони інтегрують ваш клас у поведінку мови.
**Коротко:**
- Dunder-методи визначають протокольну поведінку об'єкта.
- Вони дозволяють вашим класам поводитись "як вбудовані типи".
- Використовуйте їх лише коли є чітка семантична потреба.
125. Для чого призначений метод `__del__`?
#### Python
`__del__` це фіналізатор, який може викликатися перед знищенням об'єкта GC. Його
поведінка не детермінована, тому для керування ресурсами краще використовувати
context managers (`with`) і явне закриття.
**Коротко:**
- `__del__` не гарантує своєчасного виконання.
- Не покладайте критичний clean-up лише на нього.
- Рекомендований підхід: `with`/`try-finally`.
126. Наведіть приклад використання магічного методу `__str__` для визначення текстового представлення власного класу у Python.
#### Python
```python
class User:
def __init__(self, name: str, active: bool) -> None:
self.name = name
self.active = active
def __str__(self) -> str:
status = "active" if self.active else "inactive"
return f"User(name={self.name}, status={status})"
```
`str(user)` і `print(user)` використають `__str__`.
**Коротко:**
- `__str__` дає людинозрозуміле представлення об'єкта.
- Корисний для логів і CLI-виводу.
- Має бути коротким і читабельним.
127. Для чого використовуються `__str__` і `__repr__`?
#### Python
`__str__` орієнтований на кінцевого читача. `__repr__` орієнтований на
розробника/debug, бажано щоб був однозначним.
`print(obj)` переважно використовує `__str__`, а REPL/`repr(obj)` використовує
`__repr__`.
**Коротко:**
- `__str__` для дружнього виводу.
- `__repr__` для технічного представлення.
- Добра практика: мати обидва, якщо клас доменний.
128. Як працює operator overloading у Python і чому це корисно?
#### Python
Operator overloading це реалізація dunder-методів операторів (`__add__`,
`__sub__`, `__eq__`, ...), щоб об'єкти власного класу підтримували оператори.
```python
class Vector2:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
def __add__(self, other: "Vector2") -> "Vector2":
return Vector2(self.x + other.x, self.y + other.y)
```
**Коротко:**
- Дає природний синтаксис для доменних типів.
- Покращує виразність API.
- Важливо зберігати математично очікувану семантику.
129. Що таке inheritance (наслідування)?
#### Python
Наслідування дозволяє створити дочірній клас, який успадковує атрибути й методи
базового класу та може розширювати/перевизначати поведінку.
**Коротко:**
- Наслідування сприяє повторному використанню коду.
- Дочірній клас може перевизначати методи базового.
- Надмірна ієрархія ускладнює підтримку, тому часто краще композиція.
130. Що таке single inheritance у Python?
#### Python
Single inheritance означає, що клас має лише одного прямого батька.
```python
class Animal:
...
class Dog(Animal):
...
```
Це найпростіша і зазвичай найчитабельніша форма наслідування.
**Коротко:**
- Один дочірній клас -> один базовий клас.
- Проста модель резолюції методів.
- Часто достатня для більшості бізнес-моделей.
131. Як реалізувати наслідування у класах Python і який для цього використовується синтаксис?
#### Python
Синтаксис: `class Child(Base):`.
```python
class Base:
def greet(self) -> str:
return "hello"
class Child(Base):
def greet(self) -> str:
return "hi"
```
За потреби виклику базової логіки використовуйте `super()`.
**Коротко:**
- Наслідування задається у дужках після імені класу.
- Дочірній клас отримує API базового.
- Перевизначення дозволяє адаптувати поведінку.
132. Як отримати доступ до членів базового класу у дочірньому класі?
#### Python
Доступ можливий напряму через успадковані атрибути/методи або через `super()`.
```python
class Base:
def greet(self) -> str:
return "hello"
class Child(Base):
def greet(self) -> str:
return super().greet() + " world"
```
**Коротко:**
- Успадковані члени доступні в дочірньому класі автоматично.
- `super()` коректно викликає логіку базового класу.
- Це важливо для розширення, а не дублювання поведінки.
133. Для чого функція `super()` у наслідуванні Python, як її використовують?
#### Python
`super()` повертає проксі до наступного класу за MRO, щоб викликати його методи.
Типово використовується в `__init__` і при cooperative multiple inheritance.
```python
class Child(Base):
def __init__(self, value: int) -> None:
super().__init__()
self.value = value
```
**Коротко:**
- `super()` викликає батьківську реалізацію без жорсткого імені класу.
- Допомагає підтримувати MRO-коректність.
- Рекомендований спосіб роботи з наслідуванням.
134. Опишіть функцію `isinstance()` у Python і наведіть приклад її використання.
#### Python
`isinstance(obj, cls_or_tuple)` перевіряє, чи об'єкт належить типу або його
підкласу.
```python
isinstance(10, int) # True
isinstance(True, int) # True
isinstance("x", (str, bytes)) # True
```
**Коротко:**
- `isinstance` безпечніший за `type(obj) is ...` у поліморфному коді.
- Враховує ієрархію наслідування.
- Підтримує кортеж типів.
135. Поясніть функцію `issubclass()` у Python і наведіть приклад її застосування.
#### Python
`issubclass(Sub, Base)` перевіряє, чи клас `Sub` є підкласом `Base`.
```python
class Animal: ...
class Dog(Animal): ...
issubclass(Dog, Animal) # True
```
**Коротко:**
- Працює з класами, не з екземплярами.
- Зручно для валідації API на рівні типів.
- Враховує транзитивне наслідування.
136. Що таке multiple inheritance (множинне наслідування)?
#### Python
Multiple inheritance це спадкування одного класу від кількох базових класів.
```python
class A: ...
class B: ...
class C(A, B): ...
```
Дає гнучкість, але вимагає дисципліни у дизайні методів і `super()`.
**Коротко:**
- Один клас може успадковувати поведінку з кількох джерел.
- Корисно для mixin-підходу.
- Може ускладнювати розуміння MRO.
137. Як працює MRO (Method Resolution Order) у multiple inheritance?
#### Python
MRO визначає порядок пошуку методів у ієрархії класів. У Python використовується
алгоритм C3 linearization.
**Diamond Problem (Проблема алмазу):** Це класичний випадок, коли клас `D`
успадковується від `B` та `C`, які обидва успадковуються від `A`. MRO гарантує,
що `A` буде переглянутий лише після того, як будуть переглянуті всі його нащадки
(`B` та `C`).
```python
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.mro())
# [D, B, C, A, object]
```
Переглянути порядок можна через `ClassName.__mro__` або `ClassName.mro()`.
**Коротко:**
- MRO вирішує, з якого базового класу брати метод.
- Порядок передбачуваний і формально визначений (C3).
- Завдяки MRO Python коректно обробляє Diamond Problem.
- Для cooperative inheritance всі класи мають викликати `super()`.
138. Які переваги та недоліки використання multiple inheritance?
#### Python
Переваги:
- повторне використання поведінки з кількох джерел;
- зручні mixins для "додавання" можливостей.
Недоліки:
- складніший MRO;
- ризик конфліктів імен/поведінки;
- складніший дебаг і онбординг.
**Коротко:**
- MI потужний, але вимагає строгих правил дизайну.
- Для більшості кейсів композиція простіша.
- Використовуйте MI переважно для невеликих mixins.
139. Що таке Mixins?
#### Python
Mixin це невеликий клас з вузькою додатковою поведінкою, який призначений для
комбінування через наслідування, а не для самостійного використання.
Приклади: `TimestampMixin`, `JsonSerializableMixin`.
**Коротко:**
- Mixin додає одну конкретну можливість.
- Зазвичай не має власного повного життєвого циклу.
- Добре поєднується з multiple inheritance.
140. Що таке encapsulation (інкапсуляція) у Python?
#### Python
Інкапсуляція це приховування внутрішньої реалізації за стабільним публічним API.
У Python це реалізується переважно конвенціями і `property`, а не жорсткими
модифікаторами доступу.
**Коротко:**
- Клієнт коду працює з інтерфейсом, а не з деталями.
- Інкапсуляція зменшує зв'язування між компонентами.
- Полегшує зміну внутрішньої реалізації без ломання API.
141. Яка різниця між доступом public, private і protected?
#### Python
У Python це здебільшого naming-conventions:
- `public`: `name` — доступний усюди;
- `protected`: `_name` — внутрішнє використання за домовленістю;
- `private`: `__name` — name mangling (`_ClassName__name`), не абсолютний
захист.
**Коротко:**
- Python не має строгих access modifiers як у Java/C#.
- `_name` і `__name` це сигнали наміру для розробників.
- Реальний контроль доступу будується через API-дизайн.
142. Що таке polymorphism (поліморфізм) і як він реалізується у Python?
#### Python
Поліморфізм це можливість працювати з різними об'єктами через спільний
інтерфейс. У Python часто реалізується duck typing і протоколами.
```python
def render(obj) -> str:
return obj.to_text()
```
Будь-який об'єкт з методом `to_text` підходить.
**Коротко:**
- Один інтерфейс, багато реалізацій.
- У Python поліморфізм часто "поведінковий", а не ієрархічний.
- Це спрощує розширення системи новими типами.
143. Що таке abstraction (абстракція) у Python?
#### Python
Абстракція це виділення суттєвого API і приховування зайвих деталей реалізації.
Клієнт працює з контрактом, а не з внутрішніми кроками.
**Коротко:**
- Абстракція знижує когнітивне навантаження.
- Полегшує заміну реалізації без змін клієнтського коду.
- Реалізується через інтерфейси, ABC, протоколи, фасади.
144. Як реалізувати data abstraction?
#### Python
Підхід:
- сховати прямий доступ до внутрішніх полів (`_field`);
- надати контрольований API через методи/`@property`;
- валідувати інваріанти в setter-логіці.
```python
class Temperature:
def __init__(self, celsius: float) -> None:
self.celsius = celsius
@property
def celsius(self) -> float:
return self._celsius
@celsius.setter
def celsius(self, value: float) -> None:
if value < -273.15:
raise ValueError("invalid temperature")
self._celsius = value
```
**Коротко:**
- Data abstraction захищає інваріанти об'єкта.
- `property` дає контрольований доступ до стану.
- Внутрішні деталі можна змінювати без зміни API.
145. Що таке ABC та `@abstractmethod`?
#### Python
ABC (Abstract Base Class) це абстрактний базовий клас з модуля `abc`.
`@abstractmethod` позначає метод, який обов'язково має реалізувати підклас.
```python
from abc import ABC, abstractmethod
class Storage(ABC):
@abstractmethod
def save(self, data: bytes) -> None:
...
```
**Коротко:**
- ABC формалізує контракт ієрархії.
- `@abstractmethod` забороняє інстанціювати неповну реалізацію.
- Корисно для плагінних/розширюваних архітектур.
146. Що таке property у Python і як їх застосовують?
#### Python
`property` перетворює методи доступу в атрибутоподібний API з можливістю
валідації, обчислень або lazy-логіки.
```python
class User:
def __init__(self, name: str) -> None:
self._name = name
@property
def name(self) -> str:
return self._name
```
**Коротко:**
- `property` дає контроль доступу без зміни зовнішнього синтаксису.
- Підходить для валідації й derived-значень.
- Дозволяє еволюціонувати API без ломання клієнтів.
147. Що таке `@property`?
#### Python
`@property` це декоратор для getter-методу. Разом з `@x.setter` і `@x.deleter`
формує керований атрибут.
**Коротко:**
- `@property` дозволяє читати метод як поле.
- Допомагає інкапсулювати внутрішню реалізацію.
- Часто використовується для backward-compatible API.
148. Що таке descriptor у Python?
#### Python
Descriptor це об'єкт, який реалізує `__get__`, `__set__` або `__delete__` і
керує доступом до атрибутів іншого класу.
Через descriptor працюють `property`, `classmethod`, `staticmethod`.
**Коротко:**
- Descriptor це низькорівневий механізм атрибутного доступу.
- Дозволяє повторно використовувати логіку валідації/проксування полів.
- Це основа багатьох метапрограмних технік Python.
149. Чим відрізняються property і descriptor?
#### Python
`property` це готовий високорівневий descriptor для одного атрибута. Кастомний
descriptor це загальніший механізм, який можна перевикористати в багатьох
полях/класах.
**Коротко:**
- `property` простіший і локальний.
- Descriptor гнучкіший і масштабованіший.
- `property` фактично побудований на descriptor-протоколі.
150. Коли доцільніше використовувати property, а коли descriptor?
#### Python
Використовуйте `property`, коли логіка стосується одного-двох полів конкретного
класу. Використовуйте descriptor, коли ту саму логіку (валідація, кастинг,
ленива ініціалізація) треба повторно застосувати в багатьох класах.
**Коротко:**
- Локальна логіка поля -> `property`.
- Повторне використання політики доступу -> descriptor.
- Descriptor вигідний у великих доменних моделях.
151. Для чого використовують `setattr()`, `getattr()` і `hasattr()`? Яка між ними різниця?
#### Python
Це функції динамічного доступу до атрибутів:
- `getattr(obj, name[, default])` — прочитати атрибут;
- `setattr(obj, name, value)` — встановити атрибут;
- `hasattr(obj, name)` — перевірити наявність.
```python
value = getattr(user, "email", None)
if not hasattr(user, "active"):
setattr(user, "active", True)
```
**Коротко:**
- `getattr/setattr/hasattr` потрібні для динамічної роботи з об'єктами.
- Корисні в generic-коді, serialization, адаптерах.
- Важливо не зловживати, щоб не втратити читабельність.
152. Поясніть значення методу `__set_name__` у Python-descriptor-ах та наведіть приклад його застосування.
#### Python
`__set_name__(self, owner, name)` викликається під час створення класу і дає
descriptor-у знати ім'я атрибута, до якого його прив'язано.
```python
class Field:
def __set_name__(self, owner, name): self.name = name
```
**Коротко:**
- `__set_name__` ініціалізує descriptor контекстом класу.
- Дозволяє робити перевикористовувані валідатори полів.
- Спрацьовує один раз на етапі class creation.
153. Що таке `dataclass` і коли його варто використовувати?
#### Python
`@dataclass` автоматично генерує boilerplate (`__init__`, `__repr__`, `__eq__`).
Підходить для моделей даних без складної поведінки.
```python
from dataclasses import dataclass
@dataclass(slots=True)
class User:
name: str
active: bool = True
```
**Коротко:**
- `dataclass` скорочує код для data-моделей.
- Добрий вибір для DTO/конфігурацій.
- Для складної валідації часто потрібні інші інструменти.
154. У чому різниця між `dataclass` і Pydantic?
#### Python
`dataclass` фокусується на зручному описі структури. Pydantic додає
runtime-валідацію, парсинг і серіалізацію даних.
**Коротко:**
- `dataclass` легший і швидший для внутрішніх моделей.
- Pydantic кращий для зовнішнього вводу/API.
- Вибір залежить від потреби валідації під час виконання.
155. Що таке type hints і навіщо вони потрібні?
#### Python
Type hints це анотації типів у сигнатурах і змінних, що формують явний контракт.
Вони покращують IDE-підказки і статичний аналіз.
**Коротко:**
- Type hints підвищують зрозумілість API.
- Дають раннє виявлення класу помилок.
- Корисні навіть у динамічній мові.
156. Як працює статична перевірка типів (mypy)?
#### Python
`mypy` читає type hints і аналізує код без запуску, перевіряючи сумісність
типів. Він ловить помилки інтеграції до runtime.
**Коротко:**
- `mypy` виконує compile-time-подібну перевірку для Python.
- Працює найкраще в CI.
- Строгі режими зменшують кількість production-багів.
157. Як забезпечити type safety у Python-проєкті?
#### Python
- послідовно додати type hints у публічний API;
- увімкнути `mypy`/`pyright` у CI;
- використовувати `TypedDict`, `Protocol`, generics;
- мінімізувати `Any` і неявні касти.
**Коротко:**
- Type safety це процес, а не разова дія.
- Найбільший ефект дає CI-гейт на типи.
- Поступове підвищення strictness працює краще за "big bang".
158. Що таке `TypedDict`?
#### Python
`TypedDict` описує типізовану форму словника: які ключі очікуються і яких типів
їх значення.
```python
from typing import TypedDict
class UserPayload(TypedDict): name: str; active: bool
```
**Коротко:**
- `TypedDict` типізує `dict` з фіксованими ключами.
- Зручний для JSON-подібних структур.
- Перевіряється статичним аналізатором.
159. Що таке `Protocol` у typing?
#### Python
`Protocol` описує поведінковий контракт (structural typing): тип сумісний, якщо
має потрібні методи/атрибути, незалежно від наслідування.
**Коротко:**
- `Protocol` реалізує duck typing у статичній типізації.
- Зменшує жорстке зв'язування з конкретними класами.
- Корисний для тестованих і розширюваних API.
160. Що таке Generics у Python?
#### Python
Generics дозволяють писати типи й функції, параметризовані іншими типами. У
сучасному синтаксисі: `class Box[T]: ...`, `def first[T](...) -> T`.
**Коротко:**
- Generics роблять типи повторно використовуваними.
- Підсилюють type safety колекцій і контейнерів.
- Зменшують дублювання типізованого коду.
161. Що таке Pydantic і для чого він використовується?
#### Python
Pydantic це бібліотека для опису схем даних з runtime-валідацією, перетворенням
типів і зручною серіалізацією.
Типові кейси: FastAPI request/response моделі, конфігурація застосунку.
**Коротко:**
- Pydantic валідовує зовнішні дані під час виконання.
- Зручний для API і інтеграцій.
- Дає чіткі помилки валідації та схеми.
162. Що таке exception-и у Python?
#### Python
Exception це об'єкт, який сигналізує про помилкову або виняткову ситуацію під
час виконання коду.
**Коротко:**
- Exception-и переривають normal-flow.
- Їх треба обробляти там, де можна прийняти рішення.
- Коректна модель помилок підвищує надійність системи.
163. Які є три типи помилок у Python і чим вони відрізняються?
#### Python
- Syntax errors: помилки синтаксису до запуску;
- Runtime exceptions: помилки під час виконання;
- Logical errors: код виконується, але результат неправильний.
**Коротко:**
- Syntax/runtime ловить інтерпретатор.
- Логічні помилки ловляться тестами і рев'ю.
- Кожен тип потребує різного підходу діагностики.
164. Як використовувати `try`, `except`, `else` та `finally`?
#### Python
`try` містить ризикову операцію, `except` обробляє помилку, `else` виконується
коли помилки не було, `finally` виконується завжди (clean-up).
```python
try: data = load()
except FileNotFoundError: data = {}
else: validate(data)
finally: close_connections()
```
**Коротко:**
- `else` тримайте для коду "успішного шляху".
- `finally` для ресурсів/очищення.
- Ловіть конкретні exception-и, не "все підряд".
165. Що означає порядок `except`-категорій?
#### Python
`except` перевіряються зверху вниз, тому спочатку ставлять найконкретніші
винятки, а загальні (`Exception`) в кінці.
**Коротко:**
- Порядок `except` впливає на те, який обробник спрацює.
- Широкий `except` зверху "з'їдає" специфічні кейси.
- Це критично для правильного recovery-flow.
166. Яке призначення ключового слова `assert` у Python-коді?
#### Python
`assert` перевіряє інваріант і піднімає `AssertionError`, якщо умова хибна.
Підходить для внутрішніх перевірок розробника, не для валідації user input.
**Коротко:**
- `assert` документує "це має бути істинним".
- Не замінює продакшен-обробку помилок.
- Використовуйте для контрактів у внутрішній логіці.
167. Чим `raise` відрізняється від простого print error message у Python?
#### Python
`raise` змінює контроль потоку і сигналізує помилку викликувачеві. `print` лише
виводить текст і не зупиняє помилковий сценарій.
**Коротко:**
- `raise` це механізм обробки помилок, `print` ні.
- Exception-и можна централізовано ловити/логувати.
- `print` для діагностики, не для error-contract.
168. Як створити власний виняток (custom exception)?
#### Python
Створіть клас, що наслідує `Exception` (або конкретніший базовий виняток).
```python
class InvalidOrderError(Exception):
pass
```
**Коротко:**
- Custom exception робить помилки доменно-виразними.
- Дозволяє точково ловити потрібні кейси.
- Краще за універсальний `ValueError` скрізь.
169. Яке значення має створення custom exceptions у Python і як вони покращують обробку помилок?
#### Python
Власні exception-и формують явну error-модель домену й відділяють технічні
помилки від бізнес-правил.
**Коротко:**
- Покращують читабельність і підтримку обробників.
- Дають точнішу семантику в логах/API.
- Спрощують тестування негативних сценаріїв.
170. Як організовані exception-и у Python і яка ієрархія exception-класів?
#### Python
Ієрархія побудована від `BaseException`. Для прикладного коду майже завжди
працюють з нащадками `Exception`.
Ключові гілки: `ValueError`, `TypeError`, `KeyError`, `OSError`, `RuntimeError`.
**Коротко:**
- Exception-и утворюють дерево класів.
- Краще ловити конкретні підкласи.
- `BaseException` зазвичай не перехоплюють у бізнес-логіці.
171. Які підходи до обробки кількох різних exception-ів у Python і чому їх слід обробляти окремо?
#### Python
Підходи:
- окремі `except` для кожного типу;
- групування логічно однакових: `except (A, B):`;
- окремі recovery-стратегії для кожної категорії.
**Коротко:**
- Різні exception-и часто потребують різних дій.
- Окрема обробка зменшує приховані дефекти.
- Логи стають точнішими й кориснішими.
172. Для чого потрібно повторно піднімати (re-raise) exception у Python і коли це буває корисно?
#### Python
Re-raise (`raise` без аргументів у `except`) дозволяє додати контекст (лог,
метрики, cleanup) і передати ту саму помилку вище.
**Коротко:**
- Re-raise зберігає початковий traceback.
- Корисний для централізованої обробки на вищому рівні.
- Не "ковтайте" критичні помилки без потреби.
173. Чому використання try-except блоку варто обмежувати у програмах Python і як це впливає на продуктивність?
#### Python
`try/except` потрібен, але не має обгортати великі блоки "про всяк випадок".
Особливо дорого, коли винятки виникають часто (exception-driven flow).
**Коротко:**
- Ловіть лише очікувані помилки в вузькому місці.
- Часті exception-и погіршують продуктивність і читабельність.
- Prefer explicit checks там, де це доречно.
174. Як обробляти помилки під час роботи з файлами?
#### Python
Використовуйте `with` і ловіть конкретні винятки (`FileNotFoundError`,
`PermissionError`, `UnicodeDecodeError`, `OSError`).
```python
try:
with open(path, "r", encoding="utf-8") as f:
content = f.read()
except FileNotFoundError:
...
```
**Коротко:**
- `with` гарантує закриття файлу.
- Обробляйте конкретні I/O помилки.
- Логуйте контекст (шлях, режим, кодування).
175. Які режими роботи з файлами у Python?
#### Python
Основні режими:
- `r` читання;
- `w` перезапис;
- `a` дозапис в кінець;
- `x` створення нового файлу;
- `b` бінарний режим;
- `t` текстовий (за замовчуванням);
- `+` читання+запис.
**Коротко:**
- Режим визначає семантику безпеки й змін файлу.
- `w` затирає вміст, `a` зберігає існуючий.
- Для байтових даних використовуйте `b`.
176. Чому важливо закривати файли після операцій і що може статись, якщо залишити файл відкритим?
#### Python
Відкритий файл утримує дескриптор ОС. Якщо не закривати:
- витік file descriptors;
- блокування файлів/неповний flush;
- нестабільність на довгих процесах.
**Коротко:**
- Закриття файлу вивільняє ресурси ОС.
- `with` автоматизує безпечне закриття.
- Це критично для сервісів і batch-скриптів.
177. У чому різниця між методами `read()`, `readline()` та `readlines()` для читання файлів?
#### Python
- `read()` читає весь файл (або `n` байт/символів);
- `readline()` читає один рядок;
- `readlines()` читає всі рядки у список.
**Коротко:**
- `read()` і `readlines()` можуть бути важкими по пам'яті.
- Для великих файлів краще ітерація `for line in file`.
- Вибір залежить від обсягу і сценарію обробки.
178. Як у Python записати дані у файл і яка різниця між режимом `w` (write) та `a` (append)?
#### Python
Запис:
```python
with open("out.txt", "w", encoding="utf-8") as f:
f.write("hello\n")
```
`w` перезаписує файл з початку, `a` додає новий контент у кінець.
**Коротко:**
- `w` затирає старі дані.
- `a` зберігає існуючий вміст.
- Для журналів зазвичай використовують `a`.
179. Як працювати з великими файлами ефективно?
#### Python
- читати потоково (по рядках або чанках);
- уникати завантаження всього файлу в пам'ять;
- використовувати буферизацію і генератори;
- для колонкових/табличних даних обирати відповідні формати й парсери.
**Коротко:**
- Ключ: streaming замість full-read.
- Генератори зменшують memory footprint.
- Алгоритм обробки важливіший за мікрооптимізації.
180. Що таке контекстні менеджери?
#### Python
Контекстний менеджер керує ресурсом за протоколом `__enter__/__exit__`:
відкриття/ініціалізація та гарантоване завершення/cleanup.
**Коротко:**
- Дає безпечний lifecycle ресурсу.
- Працює через `with`.
- Зменшує кількість витоків ресурсів.
181. Як працює конструкція `with`?
#### Python
`with` викликає `__enter__` при вході в блок і `__exit__` при виході, навіть
коли сталася помилка.
```python
with open("data.txt", "r", encoding="utf-8") as f:
data = f.read()
```
**Коротко:**
- `with` гарантує cleanup.
- Робить роботу з ресурсами декларативною.
- Рекомендований для файлів, локів, транзакцій, сесій.
182. Як створити власний контекстний менеджер?
#### Python
Два підходи:
- клас з `__enter__`/`__exit__`;
- функція з `contextlib.contextmanager`.
```python
from contextlib import contextmanager
@contextmanager
def temp_flag():
yield
```
**Коротко:**
- Клас підходить для складного стану.
- `contextmanager` зручний для коротких сценаріїв.
- Обидва дають гарантований cleanup.
183. Як Python керує пам'яттю?
#### Python
CPython використовує reference counting і циклічний garbage collector. Додатково
є внутрішній алокатор (`pymalloc`) для дрібних об'єктів.
**Коротко:**
- Базовий механізм: лічильник посилань.
- GC прибирає циклічні посилання.
- Пам'ять звільняється не завжди миттєво на рівні ОС.
184. Що таке reference counting у Python і чому воно важливе для керування пам'яттю?
#### Python
Кожен об'єкт має лічильник посилань. Коли він стає нулем, об'єкт можна
звільнити. Це забезпечує швидке звільнення більшості короткоживучих об'єктів.
**Коротко:**
- Reference counting дає передбачуваний lifecycle об'єктів.
- Не вирішує циклічні посилання самостійно.
- Разом з GC формує повну модель керування пам'яттю.
185. Що таке garbage collection у Python?
#### Python
Garbage collection у CPython знаходить і прибирає недосяжні цикли об'єктів, які
не можуть бути очищені лише reference counting.
**Коротко:**
- GC доповнює reference counting.
- Особливо важливий для циклічних графів посилань.
- Його можна контролювати через модуль `gc`.
186. Як отримати адресу пам'яті об'єкта у Python?
#### Python
У CPython `id(obj)` часто відповідає адресі об'єкта в пам'яті (як ціле число).
Це діагностичний інструмент, а не стабільний зовнішній ідентифікатор.
**Коротко:**
- `id()` дає identity об'єкта.
- У CPython це зазвичай memory address.
- Не використовуйте для бізнес-логіки.
187. Для чого функція `getrefcount()` з модуля `sys`, як вона працює у Python?
#### Python
`sys.getrefcount(obj)` повертає поточний лічильник посилань на об'єкт (у
CPython). Значення зазвичай на 1 більше через тимчасове посилання аргументу.
**Коротко:**
- Це інструмент діагностики memory-behavior.
- Корисний для аналізу витоків посилань.
- Не слід покладатися на нього в прикладній логіці.
188. Поясніть на прикладах різницю між mutable та immutable-об'єктами щодо reference counting і керування пам'яттю.
#### Python
Immutable-об'єкти не змінюються, тому "зміна" створює новий об'єкт.
Mutable-об'єкти змінюються in-place, і всі посилання бачать зміну.
```python
a = "x"; b = a; a += "y" # новий об'єкт
x = [1]; y = x; y.append(2) # зміна того ж об'єкта
```
**Коротко:**
- Immutable зменшують побічні ефекти.
- Mutable ефективніші для in-place модифікацій.
- Різниця критична для копіювання і спільних reference.
189. Яка різниця між shallow copy та deep copy у Python, коли використовувати кожен підхід?
#### Python
Shallow copy копіює лише зовнішній контейнер, вкладені об'єкти залишаються
спільними. Deep copy рекурсивно копіює всю структуру.
```python
import copy
copy.copy(obj)
copy.deepcopy(obj)
```
**Коротко:**
- Shallow достатній для "плоских" структур.
- Deep потрібен для ізольованої роботи з вкладеними mutable-даними.
- Deep copy дорожчий по часу і пам'яті.
190. Що таке modules і packages у Python?
#### Python
Module це окремий `.py`-файл з кодом. Package це каталог модулів (простір імен),
що організує код у більші блоки.
**Коротко:**
- Module = одиниця коду.
- Package = структура для масштабування модулів.
- Розбиття на модулі/пакети покращує підтримуваність.
191. Як імпортувати module у Python?
#### Python
Основні форми:
- `import module`;
- `import module as m`;
- `from module import name`;
- `from package import submodule`.
**Коротко:**
- Імпорт завантажує модуль і робить його доступним у namespace.
- Alias (`as`) покращує читабельність і уникнення конфліктів.
- Віддавайте перевагу явним імпортам.
192. Які бувають типи imports?
#### Python
Поширені типи:
- абсолютні;
- відносні;
- вибіркові (`from x import y`);
- alias-імпорти (`as`);
- динамічні (`importlib`).
**Коротко:**
- Тип імпорту впливає на читабельність і підтримку.
- У продакшені переважно використовують абсолютні імпорти.
- Динамічні імпорти застосовують точково.
193. Як працює система імпортів?
#### Python
Інтерпретатор шукає модуль по `sys.path`, завантажує його один раз і кешує в
`sys.modules`. Повторний імпорт використовує кеш.
**Коротко:**
- Імпорт = пошук + виконання модуля + кешування.
- Це пояснює, чому модульний код виконується при першому імпорті.
- Циклічні імпорти виникають через порядок ініціалізації модулів.
194. У чому різниця між абсолютним і відносним імпортом?
#### Python
Абсолютний імпорт починається від кореня пакета (`from app.utils import x`).
Відносний імпорт використовує крапки (`from .utils import x`).
**Коротко:**
- Абсолютні імпорти читабельніші і стабільніші.
- Відносні зручні всередині пакета, але гірші для рефакторингу.
- Для великих проєктів краще стандартно тримати абсолютні.
195. Що робить функція `dir()`, як її можна застосовувати до modules?
#### Python
`dir(obj)` повертає список доступних атрибутів/імен об'єкта. Для модулів це
швидкий спосіб подивитися API.
```python
import math
dir(math)
```
**Коротко:**
- `dir()` допомагає в інтерактивному дослідженні модулів.
- Корисний у REPL і дебазі.
- Не замінює офіційну документацію.
196. Поясніть роль конструкції `if __name__ == "__main__":` у Python-скриптах.
#### Python
Цей блок виконується лише коли файл запущений як скрипт, а не імпортований як
модуль. Це розділяє reusable-код і CLI-entrypoint.
**Коротко:**
- Дозволяє модуль і запускати, і імпортувати.
- Запобігає небажаному виконанню при імпорті.
- Стандартний патерн для скриптів.
197. Що означає файл `__init__.py` у Python package?
#### Python
`__init__.py` позначає каталог як пакет і може ініціалізувати package-level API
(наприклад, реекспортувати класи/функції).
**Коротко:**
- Формує публічний інтерфейс пакета.
- Може містити мінімальну ініціалізацію.
- Не варто перевантажувати його важкою логікою.
198. Які best practices для стилю імпортів у Python-коді?
#### Python
- групувати імпорти: stdlib, third-party, local;
- уникати `from x import *`;
- тримати імпорти на початку файлу (крім обґрунтованих lazy-import кейсів);
- використовувати сортування/форматування (`ruff`, `isort`).
**Коротко:**
- Консистентні імпорти покращують читабельність.
- Явні імпорти зменшують конфлікти імен.
- Автоматизація інструментами прибирає ручні помилки.
199. Які популярні built-in modules існують у Python?
#### Python
Приклади популярних модулів стандартної бібліотеки:
- `os`, `sys`, `pathlib`, `json`, `datetime`, `re`,
- `collections`, `itertools`, `functools`, `typing`,
- `asyncio`, `subprocess`, `logging`, `argparse`.
**Коротко:**
- Стандартна бібліотека покриває більшість базових задач.
- Це знижує кількість зовнішніх залежностей.
- Варто добре знати stdlib перед додаванням сторонніх пакетів.
200. Що ви знаєте про пакет `collections`, які ще built-in modules використовувались?
#### Python
`collections` надає високорівневі структури:
- `Counter`, `defaultdict`, `deque`, `namedtuple`, `ChainMap`.
Типово комбінується з:
- `itertools` для ітераційних пайплайнів;
- `functools` для кешування/функц. інструментів;
- `pathlib`, `json`, `datetime` в прикладних задачах.
**Коротко:**
- `collections` розширює базові контейнери практичними структурами.
- Часто підвищує простоту й продуктивність коду.
- Добре працює в парі з `itertools`/`functools`.
201. Що повертає `sys.argv`?
#### Python
`sys.argv` повертає список аргументів командного рядка:
- `sys.argv[0]` — ім'я скрипта;
- решта елементів — передані аргументи.
**Коротко:**
- `sys.argv` це базовий інтерфейс CLI-аргументів.
- Значення приходять рядками.
- Для складних CLI краще `argparse`.
202. Який основний модуль для роботи з операційною системою у Python?
#### Python
Основний модуль це `os` (разом з `os.path`), а для сучасного API шляхів
рекомендовано `pathlib`.
**Коротко:**
- `os` дає доступ до process/env/filesystem API ОС.
- `pathlib` зручніший для роботи з шляхами.
- У реальних проєктах часто використовують обидва.
203. Як перемішати елементи списку за допомогою модуля `random`?
#### Python
Використовуйте `random.shuffle(list_)` для in-place перемішування.
```python
import random
items = [1, 2, 3, 4]
random.shuffle(items)
```
**Коротко:**
- `shuffle` змінює оригінальний список.
- Працює лише з мутабельними послідовностями (наприклад, списками).
- Для нової копії: `random.sample(items, k=len(items))`.
204. Що таке virtual environment?
#### Python
Virtual environment це ізольоване середовище Python із власними пакетами й
версіями залежностей для конкретного проєкту.
**Коротко:**
- Ізоляція прибирає конфлікти залежностей між проєктами.
- Стандартний інструмент: `venv`.
- Це базова практика для reproducible development.
205. Як працює `pip`?
#### Python
`pip` встановлює, оновлює та видаляє пакети з індексів (здебільшого PyPI),
розв'язує залежності і ставить їх у поточне середовище.
**Коротко:**
- `pip` це стандартний пакетний менеджер Python.
- Працює в межах активного venv/інтерпретатора.
- Для стабільності важливі pinned-версії.
206. Що таке `requirements.txt`?
#### Python
`requirements.txt` це файл зі списком залежностей (часто з точними версіями),
який використовується для відтворюваної інсталяції.
**Коротко:**
- Формат простий і сумісний з `pip install -r`.
- Найкраще фіксувати точні версії для production.
- Часто генерується інструментами (наприклад, `pip-tools` або `poetry export`) з
декларативного переліку/lock-файлів.
207. Що таке `pyproject.toml` і чому він став стандартом?
#### Python
`pyproject.toml` це стандартизований файл конфігурації проєкту: metadata пакета,
build-system, налаштування інструментів (ruff, pytest, mypy тощо).
**Коротко:**
- Централізує конфігурацію Python-проєкту.
- Підтримується сучасним packaging tooling.
- Зменшує кількість розрізнених config-файлів.
208. Як керувати залежностями в сучасному Python-проєкті?
#### Python
- ізолювати середовище (`venv`);
- визначати залежності в `pyproject.toml`;
- фіксувати lock/constraints для reproducibility;
- регулярно оновлювати з CI-перевірками.
**Коротко:**
- Керування залежностями має бути відтворюваним.
- Не змішуйте глобальні і проєктні пакети.
- Оновлення робіть контрольовано через тести.
209. Як правильно організувати структуру великого Python-проєкту?
#### Python
- розділити код на доменні пакети;
- мати окремі шари: `api`, `services`, `domain`, `infrastructure`;
- виділити `tests/`, `scripts/`, `configs/`;
- тримати явні межі модулів та публічний API.
**Коротко:**
- Структура має відображати домен, а не випадкові технічні деталі.
- Чіткі межі зменшують циклічні залежності.
- Тести і tooling повинні бути first-class частиною дерева.
210. У чому різниця між автоматизованим і ручним тестуванням, які переваги автоматизованого тестування?
#### Python
Ручне тестування виконується людиною крок за кроком. Автоматизоване тестування
виконується скриптами/фреймворками.
**Коротко:**
- Автотести швидкі, повторювані і придатні для CI.
- Ручне тестування корисне для exploratory UX-сценаріїв.
- У продакшені потрібна комбінація обох підходів.
211. Що таке TDD (Test-Driven Development)?
#### Python
TDD це цикл: написати failing-тест -> мінімальна реалізація -> рефакторинг.
**Коротко:**
- TDD формує API через тести.
- Дає швидкий feedback про регресії.
- Працює найкраще для модульної бізнес-логіки.
212. Які популярні фреймворки для тестування у Python?
#### Python
Найпопулярніші: `pytest`, `unittest` (stdlib), також `hypothesis` для
property-based тестів.
**Коротко:**
- `pytest` найчастіше вибирають для нових проєктів.
- `unittest` корисний як стандартний базовий інструмент.
- `hypothesis` підсилює покриття edge-cases.
213. Що таке `unittest` у Python?
#### Python
`unittest` це вбудований xUnit-фреймворк для тестів: test case класи,
assert-методи, setup/teardown, test runner.
**Коротко:**
- Частина стандартної бібліотеки.
- Підходить для консервативних середовищ без зовнішніх залежностей.
- Має більш "церемоніальний" синтаксис за pytest.
214. Що таке `pytest` і чим він відрізняється від `unittest` за синтаксисом і функціональністю?
#### Python
`pytest` це фреймворк з простим синтаксисом функційних тестів, потужними
fixtures, параметризацією і екосистемою плагінів.
**Коротко:**
- `pytest` менш шаблонний і зручніший для великих тест-сетів.
- `unittest` class-based і стандартний у stdlib.
- У сучасних проєктах переважає `pytest`.
215. Опишіть, як метод `pytest.raises` використовується для тестування виникнення конкретних exception-ів в Python-коді.
#### Python
`pytest.raises(ExpectedError)` перевіряє, що блок коду піднімає саме очікуваний
виняток.
```python
import pytest
with pytest.raises(ValueError):
int("abc")
```
**Коротко:**
- Тестує негативні сценарії явно.
- Захищає від "мовчазного" проходження помилок.
- Може перевіряти і повідомлення/атрибути винятку.
216. Що таке параметризація у тестах, як pytest підтримує її через `@pytest.mark.parametrize`?
#### Python
Параметризація запускає один тест на кількох наборах вхідних даних. У pytest це
робиться декоратором `@pytest.mark.parametrize`.
**Коротко:**
- Менше дублювання тест-коду.
- Легко масштабувати кейси.
- Краща прозорість покриття вхідних сценаріїв.
217. Як можна у pytest задати власні назви тестів при параметризованому тестуванні для кращої читабельності?
#### Python
Використовуйте параметр `ids` у `parametrize`.
```python
@pytest.mark.parametrize("value,expected", [(2, True), (3, False)], ids=["even", "odd"])
```
**Коротко:**
- `ids` робить output тест-рану зрозумілішим.
- Полегшує діагностику падінь.
- Особливо корисно при великій кількості кейсів.
218. Що таке Arrange/Setup у тестуванні, чому це важливо?
#### Python
Arrange/Setup це підготовка тестового стану: дані, об'єкти, моки, середовище.
Якісний setup робить тест детермінованим.
**Коротко:**
- Нестабільний setup = flaky-тести.
- Добрий setup ізолює тест від зовнішніх ефектів.
- Чіткий Arrange покращує читабельність сценарію.
219. Які етапи містить Cleanup/Teardown і чому це важливо?
#### Python
Teardown прибирає все, що створив тест: тимчасові файли, з'єднання, моки,
тестові записи в БД.
**Коротко:**
- Cleanup забезпечує ізоляцію між тестами.
- Зменшує побічні ефекти і флейковість.
- У pytest це зручно робити через fixture finalizers/yield-fixtures.
220. У чому різниця між методами `setUp()` та `setUpClass()` у unittest?
#### Python
`setUp()` виконується перед **кожним** тест-методом. `setUpClass()`
(classmethod) виконується **один раз** перед усіма тестами класу.
**Коротко:**
- `setUp` для пер-тестової ізоляції.
- `setUpClass` для дорогих спільних ресурсів.
- Надмірне спільне state через `setUpClass` може ускладнювати тести.
221. Що таке mock object і як він допомагає підвищити якість тестів?
#### Python
Mock object це підставний об'єкт, який імітує залежність і дозволяє контролювати
поведінку/перевіряти виклики.
**Коротко:**
- Моки ізолюють юніт від зовнішніх сервісів.
- Роблять тести швидшими і стабільнішими.
- Дають перевірку взаємодій, не лише результату.
222. Яка різниця між використанням `mock.patch` у unittest та `monkeypatch` у pytest для мокання об'єктів?
#### Python
`mock.patch` з `unittest.mock` патчить об'єкти за шляхом імпорту і має багату
API для перевірки викликів. `monkeypatch` у pytest простіше змінює
атрибути/env/dict на час тесту.
**Коротко:**
- `patch` потужніший для mock-assertion сценаріїв.
- `monkeypatch` зручний для швидких тестових підмін.
- Часто їх комбінують залежно від кейсу.
223. Яке призначення параметра `scope` у pytest fixtures?
#### Python
`scope` визначає життєвий цикл fixture: `function`, `class`, `module`,
`package`, `session`.
**Коротко:**
- Менший scope = краща ізоляція.
- Більший scope = швидший ран великих тест-сетів.
- Вибір scope це баланс швидкості та незалежності.
224. Що таке складність алгоритму і як вона визначається?
#### Python
Складність алгоритму оцінює, як ростуть витрати часу/пам'яті зі збільшенням
розміру вхідних даних `n`.
**Коротко:**
- Вимірюють часову та просторову складність.
- Оцінка зазвичай асимптотична.
- Допомагає обирати алгоритм і структури даних.
225. Поясніть поняття big O-нотації і її значення в оцінці складності алгоритмів.
#### Python
Big-O описує верхню межу зростання вартості алгоритму при великому `n`,
ігноруючи константи і нижчі члени.
**Коротко:**
- Big-O показує масштабованість, а не точний час.
- Дає мову для порівняння алгоритмів.
- Критично важлива для продуктивності на великих обсягах.
226. Які види алгоритмічної складності найчастіше зустрічаються?
#### Python
Найчастіші: `O(1)`, `O(log n)`, `O(n)`, `O(n log n)`, `O(n^2)`.
**Коротко:**
- `O(n)` і `O(n log n)` найтиповіші в прикладних задачах.
- `O(n^2)+` часто стає вузьким місцем.
- Потрібно враховувати також пам'ять, не лише час.
227. Наведіть приклади задач, які ефективно вирішуються лінійними (O(n)) алгоритмами.
#### Python
Приклади:
- пошук максимуму/мінімуму;
- фільтрація елементів;
- підрахунок частот через `Counter`;
- перевірка умов для кожного елемента.
**Коротко:**
- O(n) означає один прохід по даних.
- Це оптимально для багатьох агрегацій.
- Лінійні алгоритми добре масштабуються.
228. Як працює `lru_cache` і коли його використовувати?
#### Python
`functools.lru_cache` кешує результати функції за аргументами і повертає готове
значення при повторних викликах.
**Коротко:**
- Ефективний для pure-функцій із повторюваними вхідними даними.
- Не підходить для функцій із side effects.
- `maxsize` контролює обсяг кешу в пам'яті.
229. Як профілювати продуктивність Python-коду?
#### Python
Базові інструменти:
- `timeit` для мікровимірювань;
- `cProfile`/`pstats` для call-level профілю;
- `py-spy`/`scalene` для production-like аналізу.
**Коротко:**
- Оптимізуйте лише після вимірювань.
- Профілюйте реалістичні сценарії навантаження.
- Фіксуйте baseline до/після змін.
230. Які основні способи оптимізації Python-коду?
#### Python
- обрати правильні структури даних;
- зменшити асимптотичну складність;
- уникати зайвих копій;
- використовувати генератори/lazy pipeline;
- кешувати дорогі обчислення;
- виносити hot paths у C/Rust/NumPy, якщо потрібно.
**Коротко:**
- Найбільший приріст дає алгоритм, не синтаксичний твік.
- Оптимізація має спиратися на профілювання.
- Читабельність не варто жертвувати без виміряної вигоди.
231. Коли варто використовувати C extensions або PyPy?
#### Python
C extensions доречні для вузьких CPU-hotspots і інтеграції з нативними
бібліотеками. PyPy доречний, коли довгоживучий pure-Python код виграє від JIT.
**Коротко:**
- C extension: максимальна продуктивність ціною складності збірки.
- PyPy: потенційний приріст без переписування на C.
- Вибір робиться на основі бенчмарків вашого workload.
232. Що таке memory profiling?
#### Python
Memory profiling це вимірювання, де і скільки пам'яті споживає код у часі, щоб
знайти витоки і важкі ділянки.
**Коротко:**
- Показує memory hot spots і піки.
- Корисний для batch/data workloads.
- Інструменти: `tracemalloc`, `memory_profiler`, `scalene`.
233. Що таке GIL (Global Interpreter Lock)?
#### Python
GIL це механізм у CPython, який дозволяє лише одному thread одночасно виконувати
Python bytecode в межах процесу.
**Коротко:**
- GIL впливає на CPU-bound multithreading.
- Для I/O-bound задач threads все ще корисні.
- Для CPU-паралелізму частіше використовують multiprocessing.
234. Як глобальний інтерпретаторний лок Python (GIL) впливає на concurrency у CPython та які наслідки це має для multithreading?
#### Python
Через GIL потоки в CPython не виконують Python bytecode truly-parallel для
CPU-bound коду. Вони кооперативно перемикаються.
Наслідки:
- для I/O-bound потоків ефект добрий (очікування I/O перекривається);
- для CPU-bound задач приріст від threads зазвичай обмежений.
**Коротко:**
- GIL обмежує паралелізм потоків у CPU-bound сценаріях.
- Threads залишаються корисними для мережі/диска.
- Для CPU використовуйте процеси або нативні обчислення.
235. Як GIL впливає на продуктивність?
#### Python
GIL майже не заважає в I/O-bound задачах, але стримує throughput CPU-bound
multithreaded Python-коду в одному процесі.
**Коротко:**
- Вплив GIL залежить від типу навантаження.
- CPU-bound + threads у CPython часто не масштабується.
- Архітектуру слід обирати за профілем задач.
236. Поясніть концепцію threading у Python та як він відрізняється від multiprocessing.
#### Python
`threading` запускає кілька потоків в одному процесі зі спільною пам'яттю.
`multiprocessing` запускає окремі процеси з окремою пам'яттю.
**Коротко:**
- Threads легші і зручні для I/O-bound.
- Processes дають реальний CPU-паралелізм.
- Процеси мають вищі накладні витрати IPC/створення.
237. Коли використовувати multiprocessing замість threading?
#### Python
Коли задача CPU-bound і потребує використання кількох ядер у CPython. Приклади:
heavy parsing, image/video processing, чисельні обчислення.
**Коротко:**
- CPU-bound -> зазвичай `multiprocessing`.
- I/O-bound -> зазвичай `threading`/`asyncio`.
- Враховуйте вартість серіалізації між процесами.
238. Яка різниця між concurrency та parallelism у програмуванні, коли і яке з них доцільно використовувати?
#### Python
Concurrency це перекривання задач у часі. Parallelism це одночасне фізичне
виконання задач на кількох ядрах.
**Коротко:**
- Concurrency корисний для I/O затримок.
- Parallelism потрібен для CPU-intensive обчислень.
- У Python вибір інструмента залежить від типу bottleneck.
239. Що таке concurrency у Python?
#### Python
Concurrency у Python це організація виконання кількох задач так, щоб вони
прогресували разом: через threads, asyncio або процеси.
**Коротко:**
- Це про керування багатьма задачами, не обов'язково паралельно.
- Дозволяє підвищити throughput I/O сценаріїв.
- Потребує акуратного дизайну синхронізації та скасування.
240. У чому різниця між IO-bound і CPU-bound задачами?
#### Python
IO-bound задачі переважно чекають мережу/диск/БД. CPU-bound задачі переважно
витрачають час на обчислення процесора.
**Коротко:**
- IO-bound добре масштабується через asyncio/threads.
- CPU-bound краще масштабується через multiprocessing/нативний код.
- Спочатку визначте bottleneck через профілювання.
241. Для чого потрібен модуль `asyncio` у Python і як він дозволяє реалізувати асинхронне програмування?
#### Python
`asyncio` надає event loop, task scheduling і async primitives для кооперативної
конкурентності в I/O-bound задачах.
**Коротко:**
- Дозволяє ефективно обслуговувати багато I/O-операцій.
- Базується на `async`/`await`.
- Добре підходить для мережевих сервісів і клієнтів.
242. Чим відрізняється синхронне і асинхронне програмування у Python?
#### Python
Синхронне: виклик блокує поточний потік до завершення. Асинхронне: `await`
віддає керування event loop, поки операція очікує I/O.
**Коротко:**
- Async зменшує idle-time під час I/O.
- Sync простіший для лінійної логіки.
- Async додає складність управління задачами і cancellation.
243. Що таке `async`/`await`?
#### Python
`async def` визначає coroutine-функцію. `await` призупиняє coroutine до
готовності awaitable і повертає контроль loop.
**Коротко:**
- Це синтаксис асинхронної кооперативної моделі.
- Використовується разом з `asyncio` та async-бібліотеками.
- `await` можливий лише всередині `async def`.
244. Як працює `asyncio`?
#### Python
`asyncio` запускає event loop, який виконує tasks (coroutines), перемикаючись у
точках `await` і плануючи готові операції I/O.
**Критичне правило:** Event loop працює в одному потоці. Будь-яка блокувальна
операція (`time.sleep()`, синхронні запити `requests`, важкі обчислення) зупиняє
**весь** цикл і всі інші задачі.
**Коротко:**
- Один потік може обслуговувати багато I/O задач через кооперативність.
- Планування не витісняє задачі (non-preemptive).
- Блокувальні виклики вбивають продуктивність asyncio.
245. Що таке event loop?
#### Python
Event loop це планувальник, який відстежує події/готовність I/O і запускає
відповідні callbacks/coroutines.
**Коротко:**
- Центральний компонент asyncio-моделі.
- Керує життєвим циклом async задач.
- Визначає, коли яка coroutine продовжує виконання.
246. Як `asyncio` дозволяє реалізувати асинхронне програмування і які основні компоненти задіяні в asyncio-коді?
#### Python
Ключові компоненти:
- event loop;
- coroutine (`async def`);
- task (`asyncio.create_task`);
- awaitables (futures, tasks, coroutines);
- синхронізаційні примітиви (`Lock`, `Queue`, `Semaphore`).
**Коротко:**
- `asyncio` поєднує планування і async-API в єдину модель.
- Задачі кооперативно ділять один потік виконання.
- Архітектура має враховувати таймаути, retry і cancellation.
247. Коли `asyncio` не дає переваг?
#### Python
Коли workload CPU-bound або основні бібліотеки блокувальні й не мають async API.
Також не окупається для простих коротких скриптів.
**Вирішення для блокуючого коду:** Якщо потрібно використати блокуючу бібліотеку
в async-середовищі, використовуйте `loop.run_in_executor(None, sync_func)`, що
запустить її в окремому потоці, не блокуючи event loop.
**Коротко:**
- Async не прискорює чисті обчислення.
- Без неблокувальних I/O бібліотек вигода мінімальна.
- `run_in_executor` допомагає інтегрувати legacy/sync код.
- Складність async має бути виправдана навантаженням.
248. Як працює asyncio cancellation?
#### Python
Скасування задачі (`task.cancel()`) піднімає `CancelledError` у coroutine. Код
має коректно обробляти cleanup у `try/finally`.
**Коротко:**
- Cancellation це звичайний control-flow у async.
- Потрібно закладати обробку скасування в дизайн coroutine.
- Ігнорування cancellation призводить до "завислих" задач.
249. Що таке `contextvars`?
#### Python
`contextvars` дає context-local змінні, безпечні для async/threads сценаріїв.
Корисно для request-id, correlation-id, tenant-context.
**Коротко:**
- Альтернатива глобальному state у конкурентному коді.
- Значення ізольоване per-context.
- Покращує трасування і observability.
250. Які best practices варто застосовувати при написанні Python-коду?
#### Python
- дотримуватись PEP 8 та автоматизувати форматування;
- писати явні type hints для публічного API;
- використовувати `with` для ресурсів;
- покривати бізнес-логіку тестами;
- уникати передчасної оптимізації, профілювати;
- тримати модулі невеликими з чіткою відповідальністю;
- керувати залежностями через `pyproject.toml` + lock strategy.
**Коротко:**
- Читабельність і передбачуваність важливіші за "трюки".
- Якість тримається на автоматизації: lint, types, tests, CI.
- Архітектурна простота зменшує вартість підтримки.