Перейти к содержанию

Python: подготовка к интервью

~9 минут чтения

Python -- самый популярный язык на технических интервью: более 70% data science и backend позиций требуют Python (Stack Overflow Survey 2024). Этот файл -- hub-страница с 16 Q&A по ключевым темам: от GIL и generators до metaclasses и walrus operator. Каждый ответ -- формат "30-секундный pitch" для устной части собеседования. Детали и код -- в отдельных файлах.


Ключевые концепции

Python -- интерпретируемый, динамически типизированный язык с GIL, reference counting GC и duck typing.

Концепция Частота на интервью Сложность
Generators / yield Очень высокая Medium
Decorators Очень высокая Medium
List comprehensions Очень высокая Easy
GIL Высокая Hard
Mutable default args Высокая Easy
is vs == Высокая Easy
Context managers Высокая Medium
Shallow vs deep copy Высокая Medium
asyncio vs threading Средняя Hard
Metaclasses Низкая Very Hard

Q&A

Q: "What is the GIL and how does it affect concurrency?"

GIL (Global Interpreter Lock) -- mutex в CPython, позволяющий только одному потоку выполнять Python bytecode одновременно. Введён для упрощения memory management (reference counting не thread-safe). CPU-bound задачи: GIL -- bottleneck, используй multiprocessing (отдельные процессы с отдельными GIL). I/O-bound задачи: GIL освобождается при ожидании I/O, поэтому threading или asyncio работают нормально. C-extensions (NumPy, TensorFlow) также освобождают GIL. Python 3.13+ имеет экспериментальный free-threaded режим (PEP 703).

Q: "Explain generators and yield."

Generator -- функция с yield, которая возвращает iterator. В отличие от return, yield сохраняет состояние функции между вызовами и производит значения лениво (lazy evaluation). Генератор для 1M элементов занимает O(1) памяти вместо O(n). yield from делегирует подгенератору. С Python 3.7 StopIteration внутри генератора превращается в RuntimeError (PEP 479) -- используй return вместо raise StopIteration.

Q: "How do decorators work?"

Decorator -- higher-order function, которая оборачивает другую функцию. @decorator -- синтаксический сахар для func = decorator(func). Всегда используй @functools.wraps(func) для сохранения __name__, __doc__, __module__. Порядок применения нескольких декораторов -- снизу вверх. Встроенные: @staticmethod, @classmethod, @property. Декораторы с аргументами -- три уровня вложенности: factory -> decorator -> wrapper.

Q: "What happens with mutable default arguments?"

Default arguments создаются один раз при определении функции (def), а не при каждом вызове. Mutable default (list, dict) переиспользуется между вызовами:

def f(lst=[]):
    lst.append(1)
    return lst
f()  # [1]
f()  # [1, 1]  -- тот же список!
Решение: def f(lst=None): lst = lst if lst is not None else []

Q: "Explain is vs ==."

== проверяет equality (значения, через __eq__). is проверяет identity (один и тот же объект в памяти, id(a) == id(b)). Используй is только для сравнения с None, True, False. CPython кэширует integers -5..256 и короткие строки (interning), поэтому 256 is 256 -- True, а 257 is 257 -- implementation-dependent. Никогда не полагайся на caching в production.

Q: "Explain shallow vs deep copy."

Assignment (b = a) -- просто ссылка, тот же объект. Shallow copy (copy.copy(), list[:], list.copy()) -- копирует верхний уровень, вложенные объекты остаются ссылками. Deep copy (copy.deepcopy()) -- рекурсивно копирует всё. Gotcha: [[0]*3]*3 создаёт 3 ссылки на один список, а не 3 независимых. Правильно: [[0]*3 for _ in range(3)].

Q: "What is LEGB scope rule?"

Python ищет переменные в порядке: **L**ocal -> **E**nclosing (замыкание) -> **G**lobal -> **B**uilt-in. global x -- доступ к глобальной переменной. nonlocal x -- доступ к enclosing scope. Gotcha: если в функции есть x = ... ниже print(x), Python решает что x локальная и выдаёт UnboundLocalError.

Q: "How do context managers work?"

Context manager реализует протокол __enter__ / __exit__ для автоматического управления ресурсами через with. __exit__ вызывается даже при exception. Два способа создания: class-based (реализовать __enter__/__exit__) или generator-based (@contextmanager из contextlib). Async версия: async with и __aenter__/__aexit__. Полезные утилиты: contextlib.suppress(), contextlib.ExitStack().

Q: "Compare asyncio vs threading vs multiprocessing."

Threading: shared memory, GIL ограничивает CPU-bound, подходит для I/O-bound. Multiprocessing: отдельные процессы, true parallelism, обходит GIL, высокое потребление памяти. Asyncio: single-threaded event loop, cooperative multitasking через async/await, минимальный overhead, масштабируется до миллионов connections. Правило: CPU-bound -> multiprocessing, I/O-bound (мало connections) -> threading, I/O-bound (много connections) -> asyncio.

Q: "Explain late binding closures."

Closures в Python используют late binding -- значения переменных извлекаются в момент вызова, не создания.

funcs = [lambda: i for i in range(5)]
[f() for f in funcs]  # [4, 4, 4, 4, 4] -- все видят i=4
Решения: default parameter (lambda i=i: i), closure factory, functools.partial. Это не проблема lambda -- обычные def ведут себя так же.

Q: "What are dunder methods?"

Dunder (double underscore) methods -- специальные методы Python, определяющие поведение объектов. __init__ -- инициализация, __repr__/__str__ -- строковое представление, __eq__/__lt__ -- сравнения, __add__ -- оператор +, __len__ -- len(), __iter__/__next__ -- iterator protocol, __enter__/__exit__ -- context manager, __call__ -- callable object. __new__ -- создание объекта (до __init__), используется для singletons и immutable types.

Q: "What are metaclasses?"

Metaclass -- класс, экземплярами которого являются классы. По умолчанию metaclass -- type. class MyClass(metaclass=Meta) -- Meta.new вызывается при создании класса. Use cases: ORM (Django models), plugin registration, enforcing coding standards. На практике нужны редко. Современная альтернатива: __init_subclass__ (PEP 487, Python 3.6+) -- проще и понятнее.

Q: "Explain Python memory management."

Reference counting (основной механизм): каждый объект имеет счётчик ссылок, при достижении 0 -- удаляется. Generational GC (дополнительный): обрабатывает циклические ссылки через 3 поколения (Gen 0/½). CPython кэширует часто используемые объекты: integers -5..256, interned strings. weakref -- слабые ссылки для breaking cycles. __slots__ -- 20-50% экономии памяти за счёт отказа от __dict__.

Q: "Explain type hints in Python."

Type hints (PEP 484, Python 3.5+) -- аннотации типов для статического анализа. Не влияют на runtime. typing module: List, Dict, Optional, Union, Callable, Protocol. Проверяются через mypy или pyright. TYPE_CHECKING -- импорты только для type checker. Python 3.10+: X | Y вместо Union[X, Y], list[int] вместо List[int].

Q: "Compare dataclass vs NamedTuple."

Dataclass (3.7+): mutable по умолчанию (frozen=True для immutable), __post_init__, slots=True (3.10+), быстрее создание (8% vs NamedTuple). NamedTuple: always immutable, tuple-based, доступ по индексу и имени, более memory efficient (но dataclass с slots ещё эффективнее). Используй dataclass когда нужна mutability и performance, NamedTuple когда нужна immutability и tuple-like поведение.

Q: "What is duck typing and EAFP?"

Duck typing: "If it looks like a duck and quacks like a duck, it must be a duck." Python проверяет не тип объекта, а наличие нужных методов/атрибутов. EAFP (Easier to Ask Forgiveness than Permission): try/except вместо предварительных проверок -- идиоматичный Python подход. LBYL (Look Before You Leap): проверки условий перед действием -- менее Pythonic. EAFP предпочтителен когда ошибки редки и в многопоточном коде.

Q: "How does the walrus operator work?"

:= (Python 3.8+, PEP 572) -- assignment expression, присваивает и возвращает значение. Полезен в while (while (line := f.readline())), if (if (m := re.search(pat, s))), list comprehensions ([y for x in data if (y := f(x))]). Gotcha: низкий приоритет -- нужны скобки. Не злоупотреблять: nested walrus снижает читаемость.

Q: "Explain finally behavior with return."

finally всегда выполняется, даже при return в try/except. Если finally содержит свой return, он перезаписывает return из try/except. Значение return "захватывается" до finally (если finally не имеет return). Опасный паттерн: return в finally подавляет exceptions. Best practice: finally только для cleanup (close, release), без return.


Типичные заблуждения

Заблуждение: Python медленный, поэтому не подходит для ML

CPython интерпретатор медленный для чистого Python, но NumPy, PyTorch, TensorFlow выполняют вычисления в оптимизированном C/C++/CUDA коде. Реальный bottleneck ML-пайплайна -- data loading и preprocessing, не матричные операции. Python -- glue language, и это его сила.

Заблуждение: global и nonlocal -- одно и то же

global x обращается к module-level переменной. nonlocal x обращается к enclosing scope (замыканию). Без nonlocal присвоение x = ... внутри вложенной функции создаёт новую локальную переменную, а не модифицирует внешнюю. Без global то же самое для module-level.

Заблуждение: deepcopy всегда безопасен

copy.deepcopy() рекурсивно копирует все объекты, но не может копировать файлы, сокеты, модули и lambda-функции. Для объектов с __del__ или C-extensions deepcopy может привести к неожиданному поведению. Лучше реализовать __copy__/__deepcopy__ явно.


Вопросы на собеседовании (мета-уровень)

"Расскажите о Python за 2 минуты"

❌ Слабый ответ: "Python -- простой язык, его легко учить, он популярный"

✅ Сильный ответ: "Интерпретируемый, динамически типизированный, строго типизированный язык. GIL в CPython, reference counting + generational GC. Duck typing + EAFP-философия. Мультипарадигмальный: OOP, functional, procedural. Ключевые отличия от Java/C++: indentation-based blocks, comprehensions, generators, decorators, context managers, metaclasses."

"Что вы знаете о Python 3.10-3.13?"

❌ Слабый ответ: "Ну там pattern matching добавили..."

✅ Сильный ответ: "3.10: structural pattern matching (match/case), dataclass(slots=True). 3.11: +25% производительности (Faster CPython), exception groups. 3.12: type statement, f-string improvements, per-interpreter GIL. 3.13: экспериментальный free-threaded mode (PEP 703, --disable-gil), JIT compiler."


Детальные файлы

Файл Что внутри
особенности-языка-интервью.md 13 тем: generators, decorators, context managers, comprehensions, *args/**kwargs, dunder methods, descriptors, metaclasses, GIL, asyncio, walrus, itertools/functools, slots, dataclass vs NamedTuple, type hints, duck typing
готчас-и-трики.md 19 gotchas: mutable defaults, late binding, integer caching, is vs ==, shallow/deep copy, LEGB, truthiness, circular imports, finally+return, memory/GC, GIL, list multiplication, dict ordering, new vs init, StopIteration, walrus, functools.wraps, class vs instance vars
задачи-лайвкодинг.md Задачи для live coding
источники-python-интервью.md Ссылки на источники

Ключевые числа

Факт Значение
Integer caching range -5..256
GIL Только CPython
Free-threaded Python 3.13+ (PEP 703)
slots memory savings 20-50%
Dataclass vs NamedTuple creation speed Dataclass 8% faster
1M objects without slots ~171 MiB
1M objects with slots ~71 MiB
String join vs += loop O(n) vs O(n^2)
Generational GC generations 3 (Gen 0, 1, 2)
StopIteration -> RuntimeError Python 3.7+ (PEP 479)
Walrus operator Python 3.8+ (PEP 572)
init_subclass Python 3.6+ (PEP 487)

Источники

  1. Real Python -- Python GIL, Decorators, Metaclasses, Scope
  2. GeeksforGeeks -- Top 50+ Python Interview Questions
  3. InterviewBit -- Python Interview Questions
  4. The Hitchhiker's Guide to Python -- Common Gotchas
  5. Towards Data Science -- Multithreading, Multiprocessing, Asyncio
  6. Python PEPs -- 479, 572, 484, 487, 703