49 карточек синтаксиса на одной странице: короткий пример кода и
подпись, где обычно ошибаются. Работает Ctrl+F, у каждой карточки — своя ссылка, а те же
карточки открываются прямо в редакторе Koddo, пока ты решаешь задачу.
print сам ставит пробел между значениями и перенос строки в конце — sep и end это меняют. Для отладки печатай подпись рядом со значением: print(«total», total).
Четыре типа закрывают почти все задачи новичка: int, float, str, bool. type(x) показывает, с чем ты имеешь дело — первый шаг, когда значение ведёт себя странно.
int(), float() и str() создают новое значение нужного типа. Строка с мусором внутри падает с ValueError — оборачивай вызов в try/except, если данные приходят извне.
Деление: / , // и %
7 / 2 # 3.57 // 2 # 37 % 2 # 1597 % 10 # 7, the last digit
/ всегда возвращает float, // отбрасывает дробную часть, % даёт остаток. Пара // и % — стандартный способ разобрать число на цифры или минуты на часы.
split режет строку по разделителю и отдаёт список, join собирает список обратно в строку. Разделитель у join стоит слева: '-'.join(parts), а не parts.join('-').
replace(old, new) меняет все вхождения и возвращает новую строку; третий аргумент ограничивает число замен. Удалить символ — заменить его на пустую строку ''.
Просто проверить наличие — оператор in, нужна позиция — find, количество — count. find возвращает -1, а не ошибку, когда ничего не нашёл — не забудь это проверить.
Перебор строки по символам
word = 'koddo'count = 0for char in word: if char in 'aeiou': count += 1print(count) # 2
for идёт по строке посимвольно — отдельный индекс не нужен. Паттерн «счётчик + условие в цикле» закрывает большинство задач на подсчёт символов.
Перебор коллекций, счётчики и досрочный выход из цикла.
for: цикл по коллекции
prices = [349, 99, 199]total = 0for price in prices: total += priceprint(total) # 647
for перебирает элементы напрямую — индексы для этого не нужны. Не меняй список, по которому идёшь: удаление элементов внутри цикла пропускает соседние.
for и range: цикл по числам
for i in range(3): print(i) # 0, 1, 2for i in range(2, 10, 2): print(i) # 2, 4, 6, 8
range(stop) считает от нуля, правая граница не входит. Полная форма range(start, stop, step) задаёт начало и шаг.
while крутится, пока условие истинно — бери его, когда число шагов заранее неизвестно. Что-то внутри обязано менять условие, иначе цикл вечный.
break и continue
for price in [99, 199, -5, 349]: if price < 0: break # stop the whole loop if price > 150: continue # skip to the next item print(price) # 99
break выходит из цикла целиком, continue пропускает только текущую итерацию. Во вложенных циклах break прерывает лишь внутренний.
enumerate: индекс + элемент
steps = ['clone', 'install', 'run']for i, step in enumerate(steps, start=1): print(i, step)# 1 clone# 2 install# 3 run
enumerate отдаёт пару «номер, элемент» — это питоничнее, чем range(len(items)). start задаёт, с какого числа нумеровать.
Вложенные циклы
for row in range(1, 3): for col in range(1, 4): print(row * col, end=' ') print()# 1 2 3# 2 4 6
Внутренний цикл прокручивается целиком на каждом шаге внешнего — итераций получается rows × cols. Больше двух уровней — сигнал вынести внутренний цикл в функцию.
Индексы идут с нуля, минус считает с конца. Последний элемент — cart[-1], а вот cart[len(cart)] всегда падает с IndexError.
Добавить и удалить: append, insert, remove, pop
cart = ['coffee', 'tea']cart.append('juice') # ['coffee', 'tea', 'juice']cart.insert(0, 'water') # ['water', 'coffee', 'tea', 'juice']cart.remove('tea') # by valuelast = cart.pop() # 'juice', and it is removed
append добавляет в конец, insert — по индексу, remove ищет по значению, pop снимает по индексу и возвращает элемент. remove убирает только первое совпадение.
Срез [a:b] берёт элементы с индекса a до b, не включая b, минус считает с конца; работает и со строками. [::-1] возвращает перевёрнутую копию, исходный список не меняется.
sorted возвращает новый список, а items.sort() сортирует на месте и возвращает None — результат sort присваивать нельзя. key задаёт, по чему сравнивать элементы.
Присваивание по новому ключу добавляет пару, по существующему — перезаписывает. del падает на отсутствующем ключе, pop со вторым аргументом — нет.
Перебор словаря: keys, values, items
stock = {'coffee': 12, 'tea': 5}for name in stock: # keys print(name)for name, qty in stock.items(): print(name, qty) # coffee 12, tea 5
for по словарю идёт по ключам; пары «ключ, значение» даёт items(). Только значения — values().
Ключ в словаре: in
stock = {'coffee': 12, 'tea': 5}'coffee' in stock # True12 in stock # False, values do not countif 'tea' in stock: stock['tea'] += 1
in проверяет только ключи — значение 12 словарь «не видит». Паттерн if key in dict страхует доступ по скобкам от KeyError.
Словарное включение
prices = {'coffee': 199, 'tea': 99}sale = {n: p // 2 for n, p in prices.items()}# {'coffee': 99, 'tea': 49}cheap = {n: p for n, p in prices.items() if p < 150}# {'tea': 99}
Как списковое включение, но с парой ключ: значение слева. Удобно, например, перевернуть словарь: {v: k for k, v in d.items()}.
Неизменяемые кортежи и множества: распаковка, дубликаты, операции над наборами.
Кортеж и распаковка
point = (10, 20)x, y = point # x=10, y=20lat, lon = 55.7, 37.6 # tuple without parensfirst, *rest = [1, 2, 3, 4] # 1, [2, 3, 4]
Кортеж — неизменяемый список; распаковка раскладывает его по переменным за один шаг. Звёздочка собирает «всё остальное» в список.
set: уникальные значения
emails = ['a@m.ru', 'b@m.ru', 'a@m.ru']unique = set(emails) # {'a@m.ru', 'b@m.ru'}len(unique) # 2deduped = list(set(emails)) # back to a list
set хранит каждое значение один раз — set(список) мгновенно убирает дубли. Подвох: множество не помнит порядок; нужен порядок — бери dict.fromkeys(items).
& — пересечение, | — объединение, минус — разница. Это в разы быстрее и короче, чем сверять два списка вложенными циклами.
Что выбрать: список, кортеж, множество, словарь
cart = ['tea', 'tea'] # list: order + duplicatespoint = (55.7, 37.6) # tuple: fixed pairtags = {'sale', 'new'} # set: unique, fast lookupstock = {'tea': 5} # dict: value by key
Порядок и повторы — список; «замороженная» запись — кортеж; уникальность и быстрый in — множество; поиск по ключу — словарь. Ошибся — конвертация в один вызов: list(), set(), tuple().
return отдаёт значение и сразу выходит из функции. Без return она вернёт None: если тесты видят None — скорее всего, ты напечатал результат через print вместо return.
Параметр со значением по умолчанию можно не передавать. Не ставь дефолтом список или словарь — он создаётся один раз и живёт между вызовами; используй None и создавай внутри.
Что означает трейсбек, как поймать исключение и чем отличаются частые ошибки.
Как читать traceback
Traceback (most recent call last): File "main.py", line 4, in <module> print(total(199, '3')) File "main.py", line 2, in total return price + qtyTypeError: unsupported operand type(s) for +: 'int' and 'str'
Читай снизу вверх: последняя строка — тип ошибки и причина, строки выше — путь до места падения, твой код обычно в нижней из File-строк. Тип плюс текст ошибки — готовый запрос для поиска по этому справочнику.
Частые ошибки: что значат
199 + '3' # TypeError: mixing int and stritems[10] # IndexError: index out of rangestock['x'] # KeyError: no such keyprnit('hi') # NameError: name is not definedint('12a') # ValueError: bad value for int()
TypeError — смешал типы (чинится через int()/str()); IndexError и KeyError — обращение к тому, чего нет; NameError — опечатка в имени. Название ошибки говорит, куда смотреть, точную строку показывает traceback.
try/except: перехват ошибки
raw = 'abc'try: value = int(raw)except ValueError: value = 0print(value) # 0
Код в try выполняется до первой ошибки, except подхватывает её и идёт по запасному пути. Указывай конкретный тип: голый except прячет настоящие баги.
raise: выбросить ошибку
def set_price(price): if price < 0: raise ValueError('price must be >= 0') return priceset_price(-5) # ValueError: price must be >= 0
raise останавливает функцию и отдаёт ошибку наверх — вызывающий код решит, ловить её или падать. Плохие входные данные лучше отклонить сразу, чем вернуть «тихий» None.
Печатай подпись и значение на входе функции и перед return — сразу видно, где данные разошлись с ожиданием. Убери отладочные print перед сабмитом: лишний вывод ломает сравнение в тестах.