Циклы в Python — for и while для аналитика
Коротко
for итерирует по последовательности, while крутится, пока условие истинно. Аналитики используют циклы для обработки файлов, батчевых запросов к API, парсинга данных. На собеседованиях спрашивают range, break/continue, else у циклов и почему в pandas циклы обычно не нужны.
for — итерация по последовательности
for обходит любой итерируемый объект: список, строку, словарь, range, файл.
# Список
topics = ['SQL', 'Python', 'A/B-тесты']
for topic in topics:
print(topic)
# Строка — посимвольно
for char in 'pandas':
print(char, end=' ')
# p a n d a s
# Словарь — по ключам
config = {'host': 'localhost', 'port': 5432, 'db': 'analytics'}
for key in config:
print(f"{key}: {config[key]}")
# По парам ключ-значение
for key, value in config.items():
print(f"{key} = {value}")range — генерация числовых последовательностей
range(start, stop, step) создаёт ленивую последовательность целых чисел. stop не включается.
# 0, 1, 2, 3, 4
for i in range(5):
print(i)
# 2, 4, 6, 8
for i in range(2, 10, 2):
print(i)
# Обратный отсчёт: 5, 4, 3, 2, 1
for i in range(5, 0, -1):
print(i)range не создаёт список в памяти — это ленивый объект. range(1_000_000) не занимает памяти на миллион чисел.
while — цикл по условию
while выполняет тело, пока условие истинно. Используется, когда заранее неизвестно количество итераций.
# Ждать ответа API
import time
retries = 0
success = False
while not success and retries < 5:
response = call_api()
if response.status_code == 200:
success = True
else:
retries += 1
time.sleep(2 ** retries) # экспоненциальный бэкоффwhile используют реже, чем for. Типичные кейсы: ретраи, ожидание события, чтение данных порциями, валидация пользовательского ввода.
break и continue
break — выход из цикла досрочно. continue — перескочить к следующей итерации.
# break — найти первый отрицательный
numbers = [3, 7, -2, 5, -8]
for n in numbers:
if n < 0:
print(f"Первый отрицательный: {n}")
break
# continue — пропустить None
data = [1, None, 3, None, 5]
total = 0
for x in data:
if x is None:
continue
total += x
# total = 9else у циклов
Блок else выполняется, если цикл завершился без break. Непривычная конструкция, но на собеседованиях спрашивают.
# Проверить, есть ли простое число в списке
numbers = [4, 6, 8, 10]
for n in numbers:
if is_prime(n):
print(f"Найдено простое: {n}")
break
else:
print("Простых чисел нет")
# "Простых чисел нет" — break не сработалelse можно читать как «если break не случился». Работает и с for, и с while.
Вложенные циклы
Цикл внутри цикла. Классика — обход матрицы или генерация комбинаций.
# Таблица умножения
for i in range(1, 4):
for j in range(1, 4):
print(f"{i}x{j}={i*j}", end=' ')
print()
# 1x1=1 1x2=2 1x3=3
# 2x1=2 2x2=4 2x3=6
# 3x1=3 3x2=6 3x3=9break во вложенном цикле выходит только из внутреннего. Чтобы выйти из обоих — используйте флаг или вынесите логику в функцию с return.
Примеры для аналитика
import os
import pandas as pd
# Прочитать все CSV из папки
data_frames = []
for filename in os.listdir('data/'):
if filename.endswith('.csv'):
df = pd.read_csv(f'data/{filename}')
data_frames.append(df)
all_data = pd.concat(data_frames)
# Батчевые запросы к API
user_ids = list(range(1, 10001))
batch_size = 100
for i in range(0, len(user_ids), batch_size):
batch = user_ids[i:i + batch_size]
send_to_api(batch)
# Пагинация — while подходит идеально
page = 1
all_results = []
while True:
response = fetch_page(page)
if not response['data']:
break
all_results.extend(response['data'])
page += 1Циклы и pandas — когда НЕ нужен цикл
iterrows() существует, но почти всегда это антипаттерн. Векторные операции быстрее в 100–1000 раз.
import pandas as pd
df = pd.DataFrame({'salary': [90000, 150000, 110000]})
# Плохо — цикл по строкам
for idx, row in df.iterrows():
df.at[idx, 'tax'] = row['salary'] * 0.13
# Хорошо — векторная операция
df['tax'] = df['salary'] * 0.13
# Плохо — цикл с условием
for idx, row in df.iterrows():
if row['salary'] > 100000:
df.at[idx, 'level'] = 'senior'
else:
df.at[idx, 'level'] = 'junior'
# Хорошо — np.where или apply
import numpy as np
df['level'] = np.where(df['salary'] > 100000, 'senior', 'junior')Правило: если операция применяется к каждой строке одинаково — ищите векторный способ. Циклы в pandas оправданы только при сложной зависимости между строками.
for vs while — когда что
for — когда известно, по чему итерируем: список, range, файл, словарь. 90% циклов в аналитике.
while — когда количество итераций заранее неизвестно: ретраи, пагинация, ожидание условия, пользовательский ввод.
Частые ошибки
Модификация списка во время итерации. Удаление элементов из списка в цикле for ломает индексацию. Итерируйте по копии или используйте list comprehension.
# Баг — пропускает элементы
items = [1, 2, 3, 4, 5]
for x in items:
if x % 2 == 0:
items.remove(x) # Не делайте так
# Правильно
items = [x for x in items if x % 2 != 0]Бесконечный while. Забыли обновить условие или нет break — цикл никогда не завершится. Всегда добавляйте ограничение: счётчик или таймаут.
Цикл вместо векторной операции. for idx, row in df.iterrows() в 99% случаев заменяется на df['col'] = .... Если пишете цикл по DataFrame — сначала убедитесь, что нет встроенного способа.
Вопросы с собеседований
-- Чем for отличается от while? -- for итерирует по готовой последовательности (список, range, генератор). while проверяет условие перед каждой итерацией и работает, пока оно истинно. for — когда знаем «по чему идём», while — когда знаем «пока что выполняется».
-- Что такое range и почему это не список?
-- range — ленивый объект, который генерирует числа по запросу. range(1_000_000) занимает фиксированный объём памяти независимо от размера, в отличие от list(range(1_000_000)), который создаёт миллион элементов в памяти.
-- Когда выполняется else у цикла? -- Когда цикл завершился естественно, без break. Если break сработал — else пропускается. Работает и с for, и с while. На практике встречается редко, но на собесах спрашивают.
-- Почему iterrows в pandas — плохая идея? -- Потому что iterrows создаёт Series для каждой строки, что убивает производительность. Векторные операции в pandas (и numpy) работают в 100–1000 раз быстрее, потому что выполняются на уровне C без Python-оверхеда на каждую строку.
-- Как выйти из вложенного цикла? -- break выходит только из внутреннего цикла. Чтобы выйти из обоих: вынести во функцию и использовать return, либо завести флаг-переменную. В Python нет labeled break, как в Java.
Потренировать Python-вопросы на практике можно в тренажёре Карьерника. Подробнее про enumerate и zip, list comprehension и lambda-функции. А больше примеров вопросов — на отдельной странице.
Открыть тренажёр в Telegram — вопросы по Python, pandas, SQL и аналитике. Бесплатно.
FAQ
range(10) создаёт список из 10 элементов?
Нет. range возвращает ленивый объект range, а не список. Числа генерируются по одному при итерации. Чтобы получить список — list(range(10)). Но обычно range используют прямо в цикле, и оборачивать не нужно.
Можно ли использовать break в while True?
Да, это стандартный паттерн — бесконечный цикл с выходом по условию внутри. Типичный пример: пагинация API, чтение из очереди, ожидание события. Главное — не забыть break, иначе цикл действительно станет бесконечным.
Когда оправдан iterrows в pandas?
Когда каждая строка зависит от результата обработки предыдущей (например, кумулятивная логика со сложными условиями). Или когда нужно вызвать внешний API для каждой строки. Во всех остальных случаях — векторные операции, apply или np.where.
Чем continue отличается от pass?
continue перескакивает к следующей итерации цикла — код ниже не выполняется. pass ничего не делает — это заглушка, выполнение продолжается дальше по телу цикла. pass используют, чтобы оставить пустой блок (например, except: pass), а continue — для пропуска итераций.