**Від циклу до компрехеншн**
Компрехеншн списку — це однорядковий вираз, що будує список шляхом перетворення та/або фільтрації ітерованого об'єкта. Він замінює поширений патерн циклу:
```python
# Традиційний цикл
squares = []
for x in range(10):
squares.append(x ** 2)
# Компрехеншн списку — той самий результат
squares = [x ** 2 for x in range(10)]
```
Загальна структура:
```
[вираз for елемент in ітерований if умова]
^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
що звідки брати необов'язковий
виводити фільтр
```
**Фільтрація через if**
```python
# Лише парні квадрати
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# Лише непорожні рядки після strip()
words = [' hello ', '', ' ', 'world']
clean = [w.strip() for w in words if w.strip()]
# ['hello', 'world']
```
**Компрехеншн dict та set**
Той самий синтаксис працює для dict і set:
```python
# Компрехеншн dict
word_lengths = {w: len(w) for w in ['hello', 'world', 'python']}
# {'hello': 5, 'world': 5, 'python': 6}
# Інвертувати dict (обережно: працює лише якщо значення унікальні)
original = {'a': 1, 'b': 2, 'c': 3}
inverted = {v: k for k, v in original.items()}
# {1: 'a', 2: 'b', 3: 'c'}
# Компрехеншн set — автоматично видаляє дублікати
unique_lengths = {len(w) for w in ['hi', 'hello', 'hey', 'world']}
# {2, 5}
```
**Вирази-генератори**
Заміни `[...]` на `(...)`, щоб отримати лінивий генератор — значення обчислюються на вимогу, проміжний список не зберігається в пам'яті:
```python
# Список — будує весь список заздалегідь
total = sum([x ** 2 for x in range(10_000_000)])
# Генератор — обчислює одне значення за раз, набагато менше пам'яті
total = sum(x ** 2 for x in range(10_000_000))
# При передачі у функцію зовнішні дужки можна опустити
```
**Оператор walrus `:=` у компрехеншн (Python 3.8+)**
Іноді потрібно обчислити проміжне значення як для фільтра, так і для виводу. `:=` (walrus) дозволяє присвоїти всередині виразу:
```python
# Без walrus — обчислює strip() двічі:
clean = [w.strip() for w in words if w.strip()]
# З walrus — обчислює один раз, повторно використовує:
clean = [s for w in words if (s := w.strip())]
```
Примітка: змінна `s` «витікає» в охоплюючу область після компрехеншн — на відміну від звичайних змінних компрехеншн, які обмежені його областю.
Вкладені компрехеншн, декартовий добуток та продуктивність vs цикли
**Вкладені компрехеншн**
Вкладений компрехеншн має два цикли `for`. Зовнішній виконується першим, внутрішній — для кожної ітерації зовнішнього — той самий порядок, що у вкладених `for`:
```python
# Розгладити 2D-матрицю
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [n for row in matrix for n in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Еквівалентний цикл:
flat = []
for row in matrix: # зовнішній — перший у компрехеншн
for n in row: # внутрішній — другий у компрехеншн
flat.append(n)
# Декартовий добуток
pairs = [(x, y) for x in [1, 2, 3] for y in ['a', 'b']]
# [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]
```
**Компрехеншн з компрехеншн**
Вираз сам може бути компрехеншн, створюючи список списків:
```python
# Транспонувати матрицю
matrix = [[1, 2, 3], [4, 5, 6]]
transposed = [[row[i] for row in matrix] for i in range(3)]
# [[1, 4], [2, 5], [3, 6]]
```
**Продуктивність: компрехеншн vs цикл**
Компрехеншн списків зазвичай швидший за еквівалентні `for`-цикли у CPython, оскільки байткод для побудови списку оптимізований:
```python
import timeit
# Компрехеншн
timeit.timeit('[x*2 for x in range(1000)]', number=10000)
# приблизно 0.5 с
# Еквівалентний цикл
timeit.timeit(
'result=[]\nfor x in range(1000): result.append(x*2)',
number=10000
)
# приблизно 0.8 с — ~60% повільніше
```
Функція `map()` зі звичайною вбудованою (без lambda) є найшвидшою для чистого перетворення, але різниця рідко суттєва поза гарячими циклами:
```python
list(map(str, range(1000))) # найшвидше для однієї вбудованої функції
[str(x) for x in range(1000)] # майже так само, читабельніше
```
Коли не використовувати компрехеншн: побічні ефекти, вкладення, помилки
**Коли НЕ використовувати компрехеншн**
Компрехеншн чудові для простих, декларативних перетворень. Але вони мають межу читабельності — якщо перейти її, звичайний цикл кращий.
**Практичне правило**: якщо не можеш прочитати вголос на одному диханні — використовуй цикл.
```python
# ОК — одне перетворення, один фільтр
result = [x * 2 for x in items if x > 0]
# На межі — два фільтри, одне перетворення
result = [x.strip() for x in lines if x.strip() and not x.startswith('#')]
# Занадто складно — використовуй цикл:
result = [processed for x in data
if (y := expensive(x)) is not None
if (processed := transform(y)) > threshold]
```
**Ніколи не використовуй компрехеншн для побічних ефектів**
```python
# ПОГАНО — компрехеншн лише для побічного ефекту:
[print(x) for x in items] # створює непотрібний список None
[db.save(item) for item in items] # та сама проблема
# ДОБРЕ — використовуй цикл для побічних ефектів:
for x in items:
print(x)
```
**Поширені помилки з компрехеншн**
```python
# 1. Забувають, що walrus (:=) «витікає» за межі
clean = [s for w in words if (s := w.strip())]
print(s) # ще визначено тут — може бути несподіванкою
# 2. Двохрівневе вкладення — важко читати:
result = [[cell*2 for cell in row if cell > 0] for row in matrix if sum(row) > 0]
# Набагато зрозуміліше як функція з циклами
# 3. Компрехеншн над генератором, який вичерпаний:
gen = (x for x in range(5))
a = [x for x in gen] # [0, 1, 2, 3, 4]
b = [x for x in gen] # [] — генератор вже вичерпаний!
```
**Короткий посібник з вибору**
```
Ситуація Використовуй
───────────────────────────────── ──────────────────────────────
Просте перетворення або фільтрація list/dict/set компрехеншн
Великий датасет, обробка по одному вираз-генератор
Побічні ефекти (print, save тощо) цикл for
Складна логіка / кілька умов цикл for з if/else
Два+ рівні вкладення цикли for (читабельність перш за все)
```
def long_words(words, min_length):
return [w for w in words if len(w) > min_length]
result = long_words(["cat", "elephant", "dog", "hippopotamus"], 4)
print(result)
Напишіть функцію, яка приймає список чисел і повертає новий список, де додатні числа залишаються без змін, а від'ємні замінюються їхніми абсолютними значеннями.
def sum_of_positive_squares(numbers):
return sum(n ** 2 for n in numbers if n > 0)
result = sum_of_positive_squares([1, -2, 3, -4, 5])
print(result)
No split tab
Налаштування cookies
Ми використовуємо необхідні cookies для роботи сайту. З вашого дозволу ми також можемо зберігати налаштування сайту та використовувати аналітичні й рекламні cookies, щоб розуміти використання сайту й підтримувати розвиток проєкту.
* Ви завжди можете змінити свій вибір у налаштуваннях сайту.
Оберіть категорії cookies
Налаштування аналітики
Можна вимкнути аналітику використання платформи. Також можна надіслати в Google Analytics запит на видалення даних про використання цього сайту, пов'язаних із цим браузером.
Навчальний workspace
Навчайтеся, читаючи, запускаючи код і розв'язуючи задачі.
Практикуйте програмування з поясненнями тем, вправами, інструментами browser IDE, перевіркою regex і тренуванням друку коду в одному workspace.
Відкривайте інструменти у вкладках.Вправи, IDE-інструменти й тренажери залишаються доступними як вкладки сайту.
Перемикайтеся без втрати контексту.Переходьте між поясненнями, кодом та утилітами, зберігаючи своє місце.
Використовуйте sidebar як карту.Ліві панелі містять навігацію, налаштування, файли, libraries та керування інструментами.
PythonJavaScriptSQLite
Одна IDE, три практичні режими
Python у браузері.Запускайте невеликі скрипти, пробуйте бібліотеки й тренуйте API-запити без встановлення.
JavaScript для швидких експериментів.Перевіряйте код для браузера й порівнюйте ідеї поруч із навчальними матеріалами.
SQLite для практики з даними.Відкривайте оглядач бази даних, переглядайте таблиці, пишіть запити й вивчайте SQL локально.
ТемаIDE
Працюйте поруч у split tabs
Тримайте інструкції перед очима.Відкрийте вправу або довідкову сторінку поруч з IDE, замість постійних перемикань.
Порівнюйте інструменти під час навчання.Розміщуйте перевірки regex, пояснення та експерименти з кодом поруч, коли це потрібно для задачі.
Закрийте split, коли завершите.Workspace повернеться до однієї сфокусованої вкладки, а відкриті вкладки сайту залишаться доступними.
Тренажер друку коду
Або звичайного тексту
Тренажер розрахований на фізичну клавіатуру.Відкрийте цей розділ на ноутбуці або комп'ютері з широким екраном. На телефоні тренування друку не працюватиме коректно.
Швидкість: 0 зн/хв
0 слів/хв
Найкраща швидкість (60с): 0 зн/хв
0 слів/хв
Помилки: 0
Загальний час: 0.0 с
Щоб тренувати сліпий друк, не підглядайте на фізичну клавіатуру.