← Назад к курсу

Подробная подготовка к собеседованию на позицию Junior Python Developer (вар. 3)

Подробная подготовка к собеседованию на позицию Junior Python Developer

Данная статья подготовлена специально для тех, кто хочет углубленно изучить ключевые концепции и подготовиться к техническим вопросам на собеседовании на позицию Junior Python Developer. Здесь мы рассмотрим самые распространенные вопросы, встречающиеся на собеседованиях, и дадим развернутые ответы с примерами кода.

1. Основы Python

1.1. Управление памятью

Вопрос: Объясните механизм управления памятью в Python.

Ответ: Python управляет памятью автоматически с помощью сборщика мусора. Когда объект больше не доступен ни одной ссылке, сборщик мусора автоматически очищает его из памяти. Основными методами очистки памяти являются подсчет ссылок и mark-and-sweep.

Пример:

a = [1, 2, 3]
b = a  # теперь две ссылки на один объект
del a  # одна ссылка осталась
del b  # обе ссылки удалены, объект очищается

1.2. Ключевое слово nonlocal

Вопрос: Что значит ключевое слово nonlocal и как его использовать?

Ответ: Ключевое слово nonlocal применяется для объявления переменной из внешней области видимости (например, из вложенных функций), чтобы изменять её значение внутри внутренней функции.

Пример:

def outer():
    x = 10
    def inner():
        nonlocal x
        x += 5
        print(x)  # выведет 15
    inner()
outer()

1.3. Пакеты и модули

Вопрос: В чем отличие пакета от модуля в Python?

Ответ: Модуль — это отдельный файл .py, содержащий функции, классы и переменные. Пакет — это каталог, содержащий модули и специальный файл __init__.py, который превращает каталог в пакет.

Пример структуры пакетов:

my_package/
|-- __init__.py
|-- utils.py
|-- db.py

Импортируем модуль из пакета:

from my_package.utils import some_function
some_function()

2. Структуры данных и алгоритмы

2.1. Сложность операций над списком

Вопрос: Какова временная сложность добавления элемента в конец списка?

Ответ: Добавление элемента в конец списка выполняется за константное время — O(1), поскольку операция append добавляет новый элемент непосредственно в конец списка.

Пример:

lst = []
lst.append(10)  # O(1)

2.2. Понимание хеширования

Вопрос: Какие ограничения есть у ключей словаря в Python?

Ответ: Ключи словаря должны быть неизменяемыми объектами (такими как строки, целые числа, кортежи). Изменяемые объекты, такие как списки, нельзя использовать в качестве ключа.

Пример недопустимого ключа:

d = {}
d[[1, 2]] = "Value"  # TypeError: unhashable type: 'list'

2.3. Массивы vs. списки

Вопрос: Чем массив отличается от списка в Python?

Ответ: Массив (array.array) хранит однородные данные фиксированного размера и ограничен одним типом данных, тогда как список (list) является универсальной структурой, поддерживающей любые типы данных и динамически увеличивающейся длиной.

Пример:

import array
nums_array = array.array('i', [1, 2, 3])
print(nums_array)  # array('i', [1, 2, 3])

3. Параллелизм и многопоточность

3.1. Потоки и процессы

Вопрос: В чем различие между потоками и процессами в Python?

Ответ: Процесс запускает отдельную виртуальную машину Python, имеет свою область памяти и изолирован от других процессов. Поток выполняется в рамках одного процесса и совместно использует пространство памяти с другими потоками.

Пример параллельного исполнения:

import threading

def worker():
    print("Поток запущен.")

thread = threading.Thread(target=worker)
thread.start()

3.2. Блокировка (Lock)

Вопрос: Как предотвратить одновременный доступ к ресурсу несколькими потоками?

Ответ: Применяется блокировка (Lock), которая гарантирует эксклюзивный доступ одному потоку одновременно.

Пример блокировки:

import threading

lock = threading.Lock()

def increment_counter(counter):
    with lock:
        counter += 1
        print(f"Счётчик увеличен до {counter}")

counter = 0
threads = [threading.Thread(target=increment_counter, args=(counter,)) for _ in range(5)]
for thread in threads:
    thread.start()

4. ООП и паттерны проектирования

4.1. Паттерн Singleton

Вопрос: Что такое паттерн Singleton и как его реализовать?

Ответ: Паттерн Singleton ограничивает создание экземпляров класса одним объектом, гарантируя единственность объекта в программе.

Пример реализации:

class Singleton:
    _instance = None

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

first_instance = Singleton()
second_instance = Singleton()

print(first_instance is second_instance)  # True

4.2. Инкапсуляция

Вопрос: Что такое инкапсуляция и как защитить поля класса?

Ответ: Инкапсуляция — это сокрытие внутренних деталей реализации класса. Поля защищаются путем создания геттеров и сеттеров.

Пример:

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # закрытое поле

    def deposit(self, amount):
        self.__balance += amount

account = BankAccount(1000)
account.deposit(500)
print(account._BankAccount__balance)  # 1500 (обращение через манкинг)

5. Тестирование и отладка

5.1. Юнит-тестирование

Вопрос: Как провести юнит-тестирование функции в Python?

Ответ: Модуль unittest позволяет создавать тесты для отдельных компонентов вашего проекта.

Пример теста:

import unittest

def add(a, b):
    return a + b

class TestAddFunction(unittest.TestCase):
    def test_add_positive(self):
        self.assertEqual(add(2, 3), 5)

    def test_add_negative(self):
        self.assertEqual(add(-1, -1), -2)

if __name__ == '__main__':
    unittest.main()

5.2. Отладочные точки

Вопрос: Как добавить точку останова в коде Python?

Ответ: Точка останова добавляется с помощью функции breakpoint(), после которой выполнение останавливается, позволяя исследовать состояние программы.

Пример:

def complex_calculation(x):
    breakpoint()  # точка останова
    y = x ** 2
    z = y + 10
    return z

complex_calculation(5)

6. Дополнительные темы

6.1. Декомпозиция сложных функций

Вопрос: Почему рекомендуется избегать чрезмерно длинных функций?

Ответ: Долгие функции труднее поддерживать и тестировать. Разделение больших функций на небольшие улучшает читаемость и упрощает тестирование каждой части отдельно.

Пример правильной декомпозиции:

def calculate_total_cost(price, quantity, discount):
    total_price = price * quantity
    discounted_price = apply_discount(total_price, discount)
    return round(discounted_price, 2)

def apply_discount(amount, percentage):
    return amount * (1 - percentage / 100)

6.2. Метаклассы

Вопрос: Что такое метакласс и зачем он нужен?

Ответ: Метакласс определяет, каким образом создается класс. Обычно классы определяются ключевым словом type, однако, создавая собственный метакласс, можно контролировать процесс создания классов.

Пример метакласса:

class Meta(type):
    def __new__(meta, class_name, bases, attrs):
        print(f"Creating class {class_name}")
        return type(class_name, bases, attrs)

class MyClass(metaclass=Meta):
    pass

Заключение

Мы рассмотрели широкий спектр вопросов, важных для успеха на собеседовании на позицию Junior Python Developer. Изучив материал подробно и потренировавшись на примерах, вы сможете уверенно отвечать на большинство технических вопросов и успешно справиться с задачей.