Программирование и IT

Python: задачи с решениями

Подборка задач по возрастанию сложности — от разворота строки до генератора и декоратора-счётчика. Сначала решай сам и только потом открывай разбор: сравнение своего кода с чужим даёт больше, чем чтение готового. Все решения проверены на Python 3.

Обновлено
В этой статье

Как решать#

Порядок один и тот же: прочитать условие, записать два-три примера «вход →
ожидаемый выход», написать решение, прогнать на примерах, и только затем
смотреть разбор. Если решение не пишется десять минут — вернись к теории по
ссылке в начале раздела и попробуй снова: подглядывать в ответ раньше этого
момента смысла мало.

Полезная привычка — после каждого решения задать себе вопрос «что сломается,
если вход пустой». Половина задач ниже имеет такой край, и в разборе он
отмечен.

Строки#

Теория — в статье про строки.

Задача 1. Палиндром. Проверить, читается ли фраза одинаково в обе стороны,
не считая пробелов, знаков и регистра. "А роза упала на лапу Азора"True,
"привет"False.

def is_palindrome(s):
    clean = "".join(ch.lower() for ch in s if ch.isalpha())
    return clean == clean[::-1]

Разбор: генераторное выражение внутри join оставляет только буквы и приводит
их к нижнему регистру, а [::-1] разворачивает строку. Сравнивать нужно
очищенную строку с её разворотом, а не исходную. Пустая строка по этому коду —
палиндром, и это разумно.

Задача 2. Гласные. Посчитать количество гласных букв в русском слове.
"Программирование"7.

def count_vowels(s):
    return sum(1 for ch in s.lower() if ch in "аеёиоуыэюя")

Разбор: sum по генератору из единиц — идиома «посчитать, сколько элементов
подходит». Буква ё в списке гласных обязательна: без неё слово берёза
даст неверный ответ.

Задача 3. Фамилия и инициалы. Из строки "иванов иван иванович" получить
"Иванов И. И.".

def short_name(full):
    parts = full.split()
    return f"{parts[0].capitalize()} {parts[1][0].upper()}. {parts[2][0].upper()}."

Разбор: split() без аргумента режет по любым пробелам и не оставляет пустых
элементов, даже если между словами их несколько. Край: если частей меньше
трёх, код упадёт с IndexError — в боевом варианте стоит проверить
len(parts) == 3.

Списки и срезы#

Теория — списки и срезы.

Задача 4. Второй по величине. Найти второе по величине различное значение
списка. [5, 1, 5, 3, 9, 9]5.

def second_largest(nums):
    unique = sorted(set(nums), reverse=True)
    return unique[1] if len(unique) > 1 else None

Разбор: set убирает повторы, поэтому две девятки считаются одним значением, и
ответ — 5, а не 9. Проверка длины закрывает случай, когда все элементы
одинаковы.

Задача 5. Куски по n. Разбить список на подсписки по n элементов;
последний кусок может быть короче. ([1..7], 3)[[1, 2, 3], [4, 5, 6], [7]].

def chunks(items, n):
    return [items[i:i + n] for i in range(0, len(items), n)]

Разбор: range с шагом даёт стартовые индексы, срез сам обрезается по концу
списка — поэтому последний кусок получается короче без всяких условий. Это
главная польза среза: за границей он не бросает исключение.

Задача 6. Общие элементы с сохранением порядка. Вернуть значения, которые
есть в обоих списках, в порядке первого и без повторов.
([3, 1, 2, 3, 4], [4, 3, 5])[3, 4].

def common(a, b):
    seen = set(b)
    result = []
    for x in a:
        if x in seen and x not in result:
            result.append(x)
    return result

Разбор: множество из второго списка нужно для быстрой проверки принадлежности —
у списка она линейная, у множества постоянная. Простое set(a) & set(b) тоже
даёт правильный набор, но теряет порядок.

Словари#

Теория — в статье про словари.

Задача 7. Три самых частых слова. По строке посчитать частоты слов и
вывести три самых частых; при равенстве частот — по алфавиту.

counts = {}
for word in text.split():
    counts[word] = counts.get(word, 0) + 1
top = sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))[:3]

Разбор: get(word, 0) избавляет от проверки «есть ли ключ». Ключ сортировки —
кортеж: минус перед частотой даёт убывание по числу, второе поле сортирует
одинаково частые слова по алфавиту. На строке "кот и пёс и кот и мышь кот пёс" результат — [('и', 3), ('кот', 3), ('пёс', 2)].

Задача 8. Группировка по первой букве. Из списка слов собрать словарь
«буква → список слов».

groups = {}
for word in words:
    groups.setdefault(word[0], []).append(word)

Разбор: setdefault возвращает существующий список либо кладёт новый пустой и
возвращает его — в одну строку вместо трёх с проверкой. Обрати внимание, что
е и ё — разные ключи.

Задача 9. Суммы по категориям. Из списка пар ("чай", 120) получить
словарь с суммой по каждому названию.

totals = {}
for name, amount in sales:
    totals[name] = totals.get(name, 0) + amount

Разбор: распаковка пары прямо в заголовке цикла читается лучше, чем обращение
по индексам pair[0] и pair[1]. Для [("чай", 120), ("кофе", 250), ("чай", 80)] выйдет {'чай': 200, 'кофе': 250}.

Функции, генераторы, декораторы#

Теория — функции, генераторы
и декораторы.

Задача 10. Среднее без крайних. Функция принимает произвольное число
значений и возвращает среднее без одного минимального и одного максимального.
(1, 5, 6, 7, 100)6.0.

def trimmed_mean(*values):
    if len(values) < 3:
        raise ValueError("нужно хотя бы три значения")
    kept = sorted(values)[1:-1]
    return sum(kept) / len(kept)

Разбор: *values собирает аргументы в кортеж, sorted(...)[1:-1] отбрасывает
крайние. Проверка длины обязательна: при двух значениях срез дал бы пустой
список и деление на ноль.

Задача 11. Фибоначчи до предела. Генератор, выдающий числа Фибоначчи, не
превышающие заданное. 500 1 1 2 3 5 8 13 21 34.

def fib_upto(limit):
    a, b = 0, 1
    while a <= limit:
        yield a
        a, b = b, a + b

Разбор: одновременное присваивание a, b = b, a + b вычисляет правую часть
целиком до записи, поэтому временная переменная не нужна. Генератор не строит
список — значения приходят по одному, и предел можно поставить любой.

Задача 12. Счётчик вызовов. Декоратор, который считает, сколько раз
вызвали функцию, и хранит число в атрибуте calls.

import functools

def counted(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.calls += 1
        return func(*args, **kwargs)
    wrapper.calls = 0
    return wrapper

Разбор: счётчик живёт атрибутом самой обёртки — так его видно снаружи как
ping.calls. Строка wrapper.calls = 0 стоит после определения обёртки, но
до возврата: в момент вызова атрибут уже существует.

Файлы и исключения#

Теория — чтение файла и
исключения.

Задача 13. Сумма чисел из файла. Прочитать файл построчно, сложить числа,
нечисловые строки пропустить и сосчитать их отдельно.

def read_numbers(path):
    total, skipped = 0, 0
    with open(path, encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            try:
                total += int(line)
            except ValueError:
                skipped += 1
    return total, skipped

Разбор: try обнимает ровно одну рискованную строку, пустые строки
отсеиваются заранее и в счёт пропусков не идут. На файле из строк
10, абв, пустой, 20, 30 результат — (60, 1).

Задача 14. Своё исключение. Функция извлекает квадратный корень и бросает
собственную ошибку для отрицательного аргумента.

class NegativeError(ValueError):
    """Отрицательное значение недопустимо."""

def sqrt_int(n):
    if n < 0:
        raise NegativeError(f"корень из отрицательного: {n}")
    return round(n ** 0.5, 4)

Разбор: наследование от ValueError, а не напрямую от Exception, позволяет
вызывающему коду ловить и узко (except NegativeError), и широко
(except ValueError) — старый код продолжит работать. Тело класса состоит из
одной строки документации, и этого достаточно.

План по этапам

  1. Строки — задачи 1–3Решить палиндром, подсчёт гласных и инициалы; проверить каждое решение на двух примерах.
  2. Списки и срезы — задачи 4–6Второй по величине, разбиение на куски, общие элементы с сохранением порядка.
  3. Словари — задачи 7–9Частоты слов, группировка по первой букве, суммы по категориям.
  4. Функции и генераторы — задачи 10–12Среднее без крайних, Фибоначчи до предела, декоратор-счётчик.
  5. Файлы и ошибки — задачи 13–14Сумма чисел из файла с пропуском мусора и собственный класс исключения.

Начать изучать эту тему у себя

План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.

Начать план

Проверь себя

1.Чему равен second_largest([5, 1, 5, 3, 9, 9]) из задачи 4?

2.Сколько кусков даст chunks([1, 2, 3, 4, 5, 6, 7], 3) из задачи 5?

3.Чему равно trimmed_mean(1, 5, 6, 7, 100) из задачи 10?

4.Сколько чисел Фибоначчи, не превышающих 50, выдаст генератор из задачи 11?

Источники

  • Учебник PythonОфициальный курс: типы, структуры данных, функции, файлы
    бесплатно
  • StepikБесплатные курсы по Python с автопроверкой решений
    бесплатно
  • Встроенные функции Pythonsorted, sum, set, enumerate — то, из чего состоят решения выше
    бесплатно

Было полезно?

Ещё темы

Программирование и IT Arduino для начинающих Arduino — плата с микроконтроллером, которой можно объяснить, когда зажечь светодиод, а когда прочитать датчик. Программа пишется на упрощённом C++, заливается по USB и работает сама, без компьютера. Первое мигание светодиодом занимает минут двадцать. Программирование и IT Как изучить Python с нуля Python хорош для первого знакомства с программированием: код читается почти как текст, а стандартная библиотека закрывает большинство бытовых задач. Этот план ведёт от установки интерпретатора до собственных скриптов, покрытых тестами, — примерно за четыре месяца при занятиях около часа в день. Программирование и IT Python: срезы Срез вырезает из последовательности кусок по правилу «с какого индекса, до какого, с каким шагом». Запись компактная, но у неё два места, где почти все ошибаются: правая граница не включается, а при отрицательном шаге границы меняются местами. Разберём оба. Программирование и IT Python: генераторы Генератор выдаёт значения по одному и только тогда, когда их просят. Он не хранит всю последовательность в памяти, поэтому подходит для больших файлов и бесконечных потоков. Плата за это — генератор одноразовый: пройти по нему дважды не получится. Программирование и IT Python: декораторы Декоратор — это функция, которая принимает другую функцию и возвращает новую, с добавленным поведением. Знак `@` перед определением — просто короткая запись присваивания. Если держать это в голове, вся тема разбирается за один вечер. Программирование и IT Python: функции Функция — именованный кусок кода, который принимает значения и возвращает результат. В Python объявление занимает одну строку, но у аргументов есть тонкости: умолчания вычисляются один раз, именованные и позиционные смешиваются по правилам, а без return функция всё равно что-то возвращает.

Ещё сценарии