Вопросы по Python на собеседовании 2026 — Junior
S.
Sobes AI

Вопросы по Python на собеседовании: Junior — часть 1/3 с разбором ответов

07.03.2026 | 4 мин чтения | 2 просмотров

Вопросы по Python на собеседовании: Junior — часть 1/3 с разбором ответов

TL;DR: 8 вопросов, которые задают на Junior Python-собеседованиях — с разбором ответов, примерами кода и типичными ошибками. Mutable vs immutable, is vs ==, list vs tuple, *args/**kwargs, comprehensions, LEGB, декораторы и __init__ vs __new__.

Как пользоваться: Открой перед собеседованием → пройдись по каждому вопросу → проверь, можешь ли ответить на follow-up. Слабые места — в тренажёр.

Эта подборка — не пересказ документации. Это вопросы, которые реально задают на собеседованиях по Python в 2024–2026 годах — по отзывам с Glassdoor, Хабра и Reddit. Python уверенно держит первое место по количеству технических собеседований — 23% всех интервью по данным анализа 9 247 собесов.

Для каждого вопроса: что интервьюер на самом деле проверяет, как ответить, и где большинство кандидатов ошибается.

Содержание

Junior


1. Чем отличаются mutable и immutable типы? {#1-chem-otlichayutsya-mutable-i-immutable-tipy}

Интервьюер проверяет: понимаешь ли ты, как Python работает с памятью на базовом уровне.

Immutable (неизменяемые) — объекты, которые нельзя изменить после создания. При «изменении» создаётся новый объект:

  • int, float, bool
  • str
  • tuple, frozenset
  • bytes

Mutable (изменяемые) — можно менять содержимое без создания нового объекта:

  • list, dict, set
  • bytearray
  • Любой пользовательский класс (по умолчанию)
# Immutable — создаётся новый объект
a = "hello"
print(id(a))  # 140234866534960
a += " world"
print(id(a))  # 140234866535024 — другой id!

# Mutable — тот же объект
b = [1, 2, 3]
print(id(b))  # 140234866601280
b.append(4)
print(id(b))  # 140234866601280 — тот же id

Почему это важно на практике: mutable объект как аргумент по умолчанию — классическая ловушка:

# BAD — список создаётся один раз при определении функции
def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] — сюрприз!

# GOOD — идиоматичный паттерн
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

Типичная ошибка: говорить «строки неизменяемые, потому что Python так решил». На самом деле это решение влияет на хешируемость (только immutable объекты могут быть ключами dict и элементами set) и на потокобезопасность.

Follow-up: Можно ли изменить элемент внутри tuple? — Да, если элемент сам mutable: t = ([1, 2],); t[0].append(3) работает.


2. В чём разница между is и ==? {#2-v-chyom-raznitsa-mezhdu-is-i-}

Интервьюер проверяет: различаешь ли ты идентичность объекта и равенство значений.

  • == сравнивает значения (вызывает метод __eq__)
  • is сравнивает идентичность — указывают ли две переменные на один и тот же объект в памяти (id())
a = [1, 2, 3]
b = [1, 2, 3]

a == b  # True — значения одинаковые
a is b  # False — разные объекты в памяти

c = a
a is c  # True — один и тот же объект

Нюанс с интернированием (string/integer caching): CPython кеширует маленькие целые числа от -5 до 256 и некоторые строки:

x = 256
y = 256
x is y  # True — CPython кеширует

x = 257
y = 257
x is y  # False (в большинстве случаев)

Когда использовать is: только для сравнения с None, True, False и синглтонами. Это рекомендация PEP 8.

# GOOD
if value is None:
    ...

# BAD
if value == None:
    ...

Типичная ошибка: использовать is для сравнения строк или чисел — может работать в REPL из-за кеширования, но сломается в продакшене.

Follow-up: Что вернёт "hello" is "hello"? — Зависит от реализации. CPython может интернировать, но полагаться на это нельзя.


3. list vs tuple — когда что использовать? {#3-list-vs-tuple--kogda-chto-ispolzovat}

Интервьюер проверяет: умеешь ли ты выбирать структуру данных осознанно, а не по привычке.

- list — изменяемая последовательность. Для коллекций однородных элементов, где нужны добавление/удаление. - tuple — неизменяемая последовательность. Для фиксированных наборов, часто разнородных данных.

# list — набор пользователей (может расти)
users = ["Alice", "Bob", "Charlie"]
users.append("Diana")

# tuple — координаты точки (фиксированная структура)
point = (10.5, 20.3)
# point[0] = 15.0  # TypeError!

Ключевые различия:

- Производительность: tuple создаётся быстрее и занимает меньше памяти. CPython кеширует маленькие tuple. - Хешируемость: tuple (если все элементы immutable) можно использовать как ключ dict или элемент set. list — нельзя. - Семантика: tuple — это запись (record) с фиксированной структурой. list — это коллекция.

import sys

lst = [1, 2, 3]
tpl = (1, 2, 3)

sys.getsizeof(lst)  # 120 байт
sys.getsizeof(tpl)  # 64 байта

Типичная ошибка: говорить «tuple быстрее, поэтому всегда используй tuple». Выбор зависит от семантики, а не только от скорости. Если нужно менять — list. Если данные фиксированы — tuple.

Follow-up: Что такое NamedTuple и зачем он нужен?


Мы разобрали типы данных и сравнение объектов. Дальше — аргументы функций и синтаксический сахар Python. Это то, что проверяет умение писать идиоматичный код.


4. Что такое *args и **kwargs? {#4-chto-takoe-args-i-kwargs}

Интервьюер проверяет: знаешь ли ты механизм передачи произвольного числа аргументов.

*args собирает позиционные аргументы в tuple. **kwargs собирает именованные аргументы в dict.

def example(*args, **kwargs):
    print(f"args: {args}")      # tuple
    print(f"kwargs: {kwargs}")  # dict

example(1, 2, 3, name="Alice", age=30)
# args: (1, 2, 3)
# kwargs: {'name': 'Alice', 'age': 30}

Порядок аргументов в сигнатуре:

def func(positional, *args, keyword_only, **kwargs):
    pass

# positional — обычный аргумент
# *args — произвольные позиционные
# keyword_only — после *args, только по имени
# **kwargs — произвольные именованные

Практическое применение: декораторы, обёртки, логирование — когда нужно пробросить аргументы «как есть»:

def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

Типичная ошибка: путать распаковку (*) в вызове и сборку (*) в определении. func(*[1, 2]) — распаковка. def func(*args) — сборка.

Follow-up: Что будет, если передать *args после **kwargs в определении функции?


5. List comprehension — синтаксис и подводные камни {#5-list-comprehension--sintaksis-i-podvodnye-kamni}

Интервьюер проверяет: пишешь ли ты идиоматичный Python или «Java на Python».

# Цикл
squares = []
for x in range(10):
    squares.append(x ** 2)

# Comprehension — быстрее и читабельнее
squares = [x ** 2 for x in range(10)]

# С фильтром
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]

# Dict comprehension
word_lengths = {w: len(w) for w in ["hello", "world"]}

# Set comprehension
unique_lengths = {len(w) for w in ["hello", "world", "hi"]}

Когда НЕ использовать: если логика сложнее одной строки — comprehension превращается в нечитаемую кашу. Правило: если нужен if/else И вложенный цикл — лучше обычный цикл.

# BAD — сложно читать
result = [f(x) for x in items if x > 0 for y in x.children if y.active]

# GOOD — обычный цикл для сложной логики
result = []
for x in items:
    if x > 0:
        for y in x.children:
            if y.active:
                result.append(f(x))

Типичная ошибка: использовать comprehension для побочных эффектов: [print(x) for x in items] — создаёт бесполезный список None. Используй обычный цикл.

Follow-up: Чем list comprehension отличается от generator expression?


6. Как работает область видимости переменных? {#6-kak-rabotaet-oblast-vidimosti-peremennykh}

Интервьюер проверяет: понимаешь ли ты, где Python ищет переменные.

Python использует правило LEGB:

- Local — внутри текущей функции - Enclosing — во вложенных функциях (замыкания) - Global — на уровне модуля - Built-in — встроенные имена (print, len, range)

x = "global"

def outer():
    x = "enclosing"

    def inner():
        x = "local"
        print(x)  # "local"

    inner()
    print(x)  # "enclosing"

outer()
print(x)  # "global"

global и nonlocal:

count = 0

def increment():
    global count  # без этого — UnboundLocalError
    count += 1

def outer():
    value = 10
    def inner():
        nonlocal value  # ссылка на enclosing scope
        value += 1
    inner()
    print(value)  # 11

Типичная ошибка: не понимать, почему UnboundLocalError возникает при x += 1 без global. Python при компиляции функции видит присваивание x = и считает x локальной — до того, как она была инициализирована.

Follow-up: Что произойдёт, если назвать переменную list или print? — Она перекроет built-in в текущем scope.


Базовые механизмы языка позади. Два последних вопроса Junior-уровня — про декораторы и создание объектов. На этом собесы для джунов часто заканчиваются.


7. Что такое декоратор? {#7-chto-takoe-dekorator}

Интервьюер проверяет: понимаешь ли ты функции как объекты первого класса.

Декоратор — это функция, которая принимает другую функцию и возвращает изменённую версию. Синтаксис @ — это сахар.

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before call")
        result = func(*args, **kwargs)
        print("After call")
        return result
    return wrapper

@my_decorator
def say_hello(name):
    print(f"Hello, {name}!")

# Эквивалентно:
# say_hello = my_decorator(say_hello)

say_hello("Alice")
# Before call
# Hello, Alice!
# After call

Важно: всегда используй functools.wraps — иначе теряются __name__, __doc__ и другие метаданные оригинальной функции:

from functools import wraps

def my_decorator(func):
    @wraps(func)  # сохраняет метаданные func
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

Типичная ошибка: забыть return func(*args, **kwargs) внутри wrapper — декоратор «проглотит» возвращаемое значение.

Follow-up: Можно ли повесить несколько декораторов на одну функцию? В каком порядке они применяются?


8. Чем отличается init от new? {#8-chem-otlichaetsya-init-ot-new}

Интервьюер проверяет: понимаешь ли ты двухэтапное создание объектов в Python.

  • __new__создаёт новый экземпляр класса (аллокация памяти). Вызывается до __init__.
  • __init__инициализирует уже созданный экземпляр (заполняет атрибуты).
class MyClass:
    def __new__(cls, *args, **kwargs):
        print("__new__ called")
        instance = super().__new__(cls)
        return instance

    def __init__(self, value):
        print("__init__ called")
        self.value = value

obj = MyClass(42)
# __new__ called
# __init__ called

Когда нужен __new__: почти никогда для обычного кода. Основные случаи:

- Singleton паттерн:

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

- Наследование от immutable типов (str, int, tuple) — __init__ не может изменить уже созданный immutable объект.

Типичная ошибка: переопределять __new__ там, где достаточно __init__. Для 99% задач нужен только __init__.

Follow-up: Что произойдёт, если __new__ вернёт экземпляр другого класса?


Итого Junior: 8 вопросов. Фокус — типы данных, операторы сравнения, функции, scope, декораторы. Если уверенно отвечаешь на follow-up — ты готов к Junior-собеседованию по Python.

Чего НЕ спрашивают на Junior

  • Алгоритмы сортировки наизусть — могут попросить решить простую задачу, но не заставят писать quicksort.
  • Metaclasses и дескрипторы — это Senior-территория.
  • Asyncio — от джуна не ждут знания асинхронности.
  • Внутреннее устройство CPython — GIL, garbage collection — это Middle+.

Как готовиться к Junior Python-собеседованию

  • Пройдись по всем 8 вопросам — если не можешь объяснить своими словами, разберись глубже.
  • Напиши код руками — не читай ответы, а пиши. Открой REPL и проверь каждый пример.
  • Прорешай 10-15 задач на LeetCode Easy — list, dict, string операции.
  • Подготовь пет-проект — хотя бы один, который можешь показать и обсудить.

Как попробовать Sobes AI

Sobes AI — AI-помощник для технических собеседований. Как он поможет с этими вопросами:

  1. Скачай приложение на sobesai.app
  2. Запусти тренировку — AI задаёт вопросы из реальных собеседований
  3. Получи обратную связь — что ответил хорошо, где слабые места
  4. Пройди mock-собеседование — имитация реального интервью с follow-up вопросами
  5. Используй на реальном собесе — AI подсказывает в реальном времени

Готовитесь к собеседованию?

Sobes AI слушает вопросы интервьюера и генерирует ответы в реальном времени.

Скачать Sobes AI