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.7StopIterationвнутри генератора превращается в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=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 -- значения переменных извлекаются в момент вызова, не создания.
Решения: 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.
typingmodule: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) |
Источники¶
- Real Python -- Python GIL, Decorators, Metaclasses, Scope
- GeeksforGeeks -- Top 50+ Python Interview Questions
- InterviewBit -- Python Interview Questions
- The Hitchhiker's Guide to Python -- Common Gotchas
- Towards Data Science -- Multithreading, Multiprocessing, Asyncio
- Python PEPs -- 479, 572, 484, 487, 703