Коллекции и структуры данных: вопросы для собеседования (часть 7)

Списки, словари, множества, кортежи — базовые структуры данных Python, без которых не обойтись ни в анализе, ни на собеседовании. Спрашивают про сложность операций, разницу между list и tuple, когда использовать set вместо list. Понимание коллекций показывает, что кандидат пишет эффективный код, а не просто «работающий».

Генераторы списков и встроенные функцииЦиклы и условияИсключения и отладкаРабота с файлами: JSON и CSVФункции и аргументыИтераторы и генераторыNumPy: основыPandas и DataFrameСинтаксис и типы данных

Вопросы 3135 из 40

31Есть очередь задач `q = deque(['task1', 'task2'])`. Что произойдёт после вызова `q.appendleft('urgent')`?
AЭлемент `'urgent'` добавится в конец очереди: результат `deque(['task1', 'task2', 'urgent'])` как при обычном `.append()`
BЭлемент `'urgent'` добавится в начало очереди: результат `deque(['urgent', 'task1', 'task2'])` для метода `.appendleft()`
CГолова очереди заменится на `'urgent'`: результат `deque(['urgent', 'task2'])` после перезаписи старого первого элемента
DБудет ошибка `AttributeError`: тип `deque` метод `.appendleft()` в стандартной реализации модуля не поддерживает
Ответ: Метод `.appendleft(x)` добавляет элемент в начало `deque` за время O(1).

`deque` (двусторонняя очередь) поддерживает быстрое добавление и удаление с обоих концов. Метод `.appendleft('urgent')` вставит элемент в начало, и результат будет `deque(['urgent', 'task1', 'task2'])`. Для обычного `list` вставка в начало через `.insert(0, x)` работает за O(n), потому что сдвигает все элементы. Для `deque` такая операция стоит O(1), что и делает его удобным как очередь с приоритетом по концу вставки.

Подробный разбор →
32Есть словарь `user = {"id": 7}`. Поле `"profile"` может отсутствовать, а если присутствует, возраст лежит в `user["profile"]["age"]`. Как безопасно получить возраст без `KeyError`, чтобы при отсутствии вернулось `None`?
A`user.get('profile', {}).get('age')`: при отсутствии `profile` берётся пустой словарь и далее `.get`
B`user['profile'].get('age')`: обращение по ключу `profile` через прямую индексацию словаря
C`user.get('profile').get('age')`: цепочка из двух `.get` без подстраховки на промежуточном шаге
D`user['age']`: чтение возраста напрямую из корня словаря по одному ключу
Ответ: Берите промежуточный словарь через `.get(key, {})`, а затем уже доставайте вложенное значение.

Если `"profile"` отсутствует, то `user.get("profile", {})` вернёт пустой словарь, и `.get("age")` у него вернёт `None` без исключения. Вариант `user.get("profile").get("age")` опасен: при отсутствии ключа `.get("profile")` вернёт `None`, а у `None` нет метода `.get()`. Прямое обращение `user["profile"]` даст `KeyError`, а `user["age"]` ищет возраст не там.

Подробный разбор →
33Вы считаете количество событий по типу в словаре `counts = {}`. Приходит значение `event_type`. Какой код корректно увеличивает счётчик, даже если ключа ещё нет?
A`counts[event_type] += 1`: прямое увеличение счётчика по ключу без проверки на наличие
B`counts[event_type] = counts.get(event_type, 0) + 1`: безопасный шаблон с дефолтом `0` при отсутствии ключа
C`counts.get(event_type) += 1`: попытка присвоить значение результату вызова `.get()`
D`counts.items(event_type, 0) + 1`: вызов `items()` с аргументами и инкремент пары значений
Ответ: Шаблон `d[k] = d.get(k, 0) + 1` безопасно работает, даже если ключа `k` ещё нет.

Шаблон `d[k] = d.get(k, 0) + 1` безопасен: метод `.get(k, 0)` вернёт текущее значение, а если ключа нет — вернёт 0, после чего можно прибавить 1 и записать в словарь. Прямой `counts[event_type] += 1` упадёт с `KeyError` при первом появлении ключа. Конструкция `counts.get(...) += 1` невалидна синтаксически: нельзя присваивать значение результату вызова. Метод `.items()` возвращает пары и не принимает аргументов.

Подробный разбор →
34Даны два счётчика:\n```python\nfrom collections import Counter\nc1 = Counter({'a': 3, 'b': 1})\nc2 = Counter({'a': 2, 'b': 2})\n```\nЧто вернёт выражение `c1 - c2`?
A`Counter({'a': 4, 'b': 3})`: поэлементная сумма счётчиков, ключи `a` и `b` суммируются по двум объектам
B`Counter({'a': 1, 'b': -1})`: разница по ключам с сохранением отрицательных значений в итоговом объекте
C`Counter({'a': 1})`: разница по ключам с автоматическим отбрасыванием нулевых и отрицательных значений в итоге
D`Counter()`: пустой счётчик, ведь операция вычитания обнуляет общие ключи в обоих исходных объектах
Ответ: Вычитание `Counter` отбрасывает нулевые и отрицательные значения, оставляя только положительные.

При вычитании `c1 - c2` считается разница по каждому ключу: `a` = 3 − 2 = 1, `b` = 1 − 2 = −1. Однако `Counter` при арифметических операциях автоматически отбрасывает ключи с нулевым или отрицательным значением. Поэтому `b` не попадёт в результат, и итог — `Counter({'a': 1})`. Чтобы сохранить отрицательные значения, используют метод `c1.subtract(c2)`, изменяющий объект на месте.

Подробный разбор →
35Есть `d = deque(['a', 'b', 'c'])`. Что произойдёт после `d.rotate(-1)`?
AПеремещает последний элемент в начало: `deque(['c', 'a', 'b'])`
BУдаляет первый элемент и сдвигает остальные: `deque(['b', 'c'])`
CПеремещает первый элемент в конец: `deque(['b', 'c', 'a'])`
DПереворачивает всю очередь задом наперёд: `deque(['c', 'b', 'a'])`
Ответ: `.rotate(-1)` сдвигает элементы влево на одну позицию: первый элемент перемещается в конец.

Метод `.rotate(n)` выполняет циклический сдвиг элементов. Положительный `n` сдвигает вправо (с конца в начало), отрицательный — влево (с начала в конец). При `d.rotate(-1)` элемент `'a'` переместится в конец, и результат будет `deque(['b', 'c', 'a'])`. Это эквивалентно `d.append(d.popleft())`, но выполняется за одну операцию.

Подробный разбор →
12345678

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать Python в Telegram

Другие темы: Python

Генераторы списков и встроенные функцииЦиклы и условияИсключения и отладкаРабота с файлами: JSON и CSVФункции и аргументыИтераторы и генераторыNumPy: основыPandas и DataFrameСинтаксис и типы данных