На конец 2023 года язык программирования Python является самым популярным по индексу TIOBE. Что касается работы, то по количеству вакансий в мире язык Python занимает второе место (после JavaScript/TypeScript). Поэтому у соискателей на должность, где требуется Python, возникает потребность подготовки к собеседованиям.

В этой статье я расскажу о том, как используя Python, можно написать desktop-приложение для ОС Windows, которое поможет быстро, эффективно и абсолютно бесплатно подготовиться к собеседованиям по Python.

Для кого это приложение и какие вопросы будут затронуты

Вы можете подавать резюме на любую профессию, где требуется Python: бекенд-разработчик, аналитик данных, тестировщик, специалист по Data Science или машинному обучению, но в любом случае вы должны обладать необходимой фундаментальной базой. В этом приложении я аккумулировал все возможные вопросы – как вопросы с реальных собеседований (реальные кейсы), так и вопросы, которые, как говорится, вы должны “must know”. Все эти вопросы я разбил на 7 тематических групп:

  1. Базовый синтаксис Python (217 вопросов)

  2. Объектно-ориентированное программирование (ООП) (110 вопросов)

  3. Правила оформления кода (PEP8, PEP257) (27 вопросов)

  4. Структуры данных на Python (69 вопросов)

  5. Алгоритмы на Python (39 вопросов)

  6. Git (64 вопроса)

  7. Базы данных и SQL запросы (58 вопросов)

В этом приложении нет фреймворков типа Django или специализированных библиотек типа NumPy. Если интервьюер поймет, что у вас нет фундаментальной базы, то он не будет спрашивать про фреймворки, а собеседование очень быстро закончится.

Также в этом приложении нет задач с LeetCode. В последнее время среди кандидатов осуществляется практика заучивать алгоритмы решения задач на LeetCode, поэтому интервьюеры начали придумывать свои задачи (которые позже попадают на опять же LeetCode).

Тем не менее, в приложении есть классические олимпиадные задачи на основные алгоритмы, но их мало. Уметь решать эти задачи – это своего рода правила хорошего тона в программировании.

Актуальность вопросов

При формировании списка вопросов я старался максимально актуализировать их содержание в соответствии с последними изменениями в синтаксисе языка. Например, существует вопрос про конструкцию match/case, которая появилась не так давно - в Python 3.10.

И наоборот, здесь отсутствуют устаревшие конструкции. Например, кто помнит о функции format() при работе со строками? Когда появились f-строки, о функции format() все забыли, поэтому её здесь и нет. А f-строки есть.

Придумываем функционал приложения

Грубо говоря, функционал приложения – это то, что оно умеет делать. А умеет делать оно следующее: создавать пользователей, вести их статистику (на сколько вопросов они ответили верно, сколько времени они провели на собеседованиях), загружать csv-файлы с вопросами, гибко настраивать собеседования, озвучивать вопросы.

Довольно много получается, поэтому оптимальным вариантом будет использовать парадигму объектно-ориентированного программирования (ООП), но помимо классов и экземпляров будет много-много вспомогательных функций.

Для реализации приложения я использовал самую последнюю версию интерпретатора Python на момент написания статьи – Python 3.12.

Создаем графический интерфейс

Не знаю, как другие разработчики, но мне всегда сначала хочется написать графический интерфейс. И начинаю я с блокнота. Не того, что notepad.exe, а с обычного реального блокнота для рисунков. Вот, что я нарисовал на самом раннем этапе разработки:

Figma бекендера
Figma бекендера

Теперь надо выбрать библиотеку для Python, в которой можно создать графический интерфейс. В Python есть встроенный модуль tkinter. Но если его использовать, то ваше приложении будет похоже на приложения времен Windows 95. Поэтому мы используем что-то современное – стороннюю библиотеку customtkinter. Но почему же не PyQt? Помните принцип KISS? Keep it simple, stupid! Для простого проекта я буду использовать более простые технологии.

Вот что получилось.

Пользователи, управление пользователями

Из всех возможных способов реализации управления юзерами в приложении самым оптимальным является создание базы данных. Можно использовать стандартную библиотеку Python sqlite3, но тогда будем писать чистые SQL-запросы в базу данных, а я не хочу. Поэтому давайте используем какую-нибудь популярную ORM. Я выбрал SQLAlchemy. Вот так будет выглядеть код для создания базы данных пользователей:

import os
from typing import Type

from sqlalchemy import create_engine
from sqlalchemy import DateTime, Integer, JSON, String
from sqlalchemy import MetaData
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column

from settings import DATABASE_NAME

engine = create_engine(f'sqlite:///{DATABASE_NAME}', echo=False)
metadata = MetaData()


class Base(DeclarativeBase):
    pass


class User(Base):
    """A class representing user's data in the app.

    Attributes:
        __tablename__ (str): The name of the table in the database.
        id: The unique identifier of the user.
        user_name: The name of the user.
        last_enter_date: The date and time of the user's last login.
        interviews_duration: The total duration of interviews
        for the user in seconds.
        progress: The user's progress data stored in JSON format.
    """
    __tablename__ = 'users'

    id: Mapped[int] = mapped_column(primary_key=True)
    user_name: Mapped[str] = mapped_column(String(25))
    last_enter_date: Mapped[Type] = mapped_column(DateTime, nullable=True)
    interviews_duration: Mapped[int] = mapped_column(Integer)
    progress: Mapped[Type] = mapped_column(JSON)


def create_db() -> None:
    """Creates database as a SQLite-file"""
    if not _is_db_created():
        Base.metadata.create_all(engine)


def _is_db_created() -> bool:
    """Checks DB existence in the root folder."""
    return os.path.exists(f'./{DATABASE_NAME}')

Как видно из кода, у нас есть удобный инструмент для хранения прогресса пользователя – формат JSON, а также инструмент для работы с датами и временем DateTime.

Hidden text

Небольшое замечание: с помощью SQLAlchemy также можно работать с базой данных через чистые SQL-запросы.

В приложении мы будем использовать файловую СУБД SQLite – это, пожалуй, самый лучший, если не единственный вариант в данном случае.

Решаем вопрос со списком вопросов

Особого смысла загружать в базу данных список вопросов я не вижу. А что, если у нас список вопросов будет храниться в каком-нибудь файле, который можно будет очень легко править с помощью Microsoft Excel или Google Таблиц. Существует такой текстовый формат CSV, предназначенный для представления табличных данных. Его мы и будем использовать для хранения вопросов. Хорошей новостью является то, что в Python существует инструмент для работы с CSV – одноименная стандартная библиотека. Мы через менеджера контекста открываем файл и переводим данные CSV-файла в битовый поток, и десериализуем этот поток в список кортежей Python.

Имитируем голос интервьюера

Наше приложение может воспроизводить голосом задаваемые вопросы. Эта технология называется TTS (text-to-speech). В Python существует сторонняя библиотека pyttsx3. Проблема в том, что при выполнении чтения текста у нас приложение будет «заморожено» на время воспроизведения. Поэтому давайте переложим выполнение чтения текста на другой поток центрального процессора. Для этого использует стандартную библиотеку threading.

Логика приложения

На данный момент не существует технологии, когда люди что-то наговаривают в микрофон, а нейросеть оценивает, насколько правильно и развернуто они ответили. Тот, кто реализует такую возможность станет миллиардером.

В нашем случае приложение вам задает вопрос, а вы будете, во-первых, учиться слушать вопрос, а, во-вторых учиться отвечать на него, после чего нажмете кнопки «Я правильно ответил на вопрос» и «Я не знаю, следующий вопрос». Но, что если у вас есть сомнений относительно правильности ответа?

Для этого существует третья кнопка – «Посмотреть ответ на вопрос». Нажав на нее, у вас в новом окне появится ответ на вопрос и вы можете посмотреть правильно ли вы ответили или нет.

Что можно было сделать лучше

В первую очередь я жалею, что не стал вести разработку через тестирование (англ. test-driven development, TDD). Когда я добавлял новые функции, меня не покидало ощущение, что все ранее созданное сломалось, а запустить pytest или unittest я не могу.

Я также не стал писать «стильный, модный и молодежный» код с использованием библиотеки dataclasses и тамошними декораторами. Поэтому я написал самый обычный код по старинке.

Ну и еще один момент: вы помните, что классы должны быть закрыты для модификации (Open-Closed Principle). Надо было бы сделать все атрибуты приватными и тонко настроить их поведение через геттеры и сеттеры, создав объекты-свойства с помощью декоратора @property. А еще определить коллекцию __slots__ для каждого класса.

Что в итоге получилось

Полный код программы доступен в публичном репозитории в моем профиле на GitHub

Там же вы найдете ссылки на скачивание EXE-версии программы.

А можно на видео показать, как пользоваться приложением

Покажу и расскажу. Вот видео на YouTube. Всем спасибо, всем пока.

Комментарии (15)


  1. dimitrii_z
    10.12.2023 19:54

    Очень интересный проект, но немного не раскрыта цель. Вопрос автору: вы как тимлид обучаете джунов в команде, или для репетиторства, или для чего было сделано? Понятно что не для себя, раз вы это всё знаете.

    Также по поводу format() и другого устаревшего кода: они-то может сейчас с нуля не используется, но в давно существующих проектах, старых модулях зависимостей и прочем вполне можно встретить. Так что есть смысл хоть один вопрос оставить типа "а для чего это может быть нужно?". А там уже можно нагуглить подробности.


    1. IvanZaycev0717 Автор
      10.12.2023 19:54

      спасибо за комментарий. Отвечаю: нет я не обучаю джунов и не занимаюсь репетиторством. И вообще являюсь ярым противником всяких популярных IT-курсов. Проект был сделан в первую очередь для моего портфолио на GitHub, меня со времен незабвенного Delphi тянет к графическим интерфейсам. По поводу format() абсолютно с вами согласен, здесь я не подумал


      1. bert2000
        10.12.2023 19:54

        Почему вы не умеете генерировать интерфейсы?


        1. IvanZaycev0717 Автор
          10.12.2023 19:54

          вообще не понимаю, о чем вы))))


  1. alex_kag
    10.12.2023 19:54

    Уважаемый автор, есть вопрос, в описании к репозиторию, можно подумать, что проект так же должен запускаться и под Linux. Но..... оно же падает даже на этапе pip install


    1. 0Bannon
      10.12.2023 19:54

      Потому что желательно использовать 'pathlib' вместо 'os' в таких случаях.


    1. IvanZaycev0717 Автор
      10.12.2023 19:54

      ошибка ModuleNotFoundError: no module named "название модуля"? Или что то другое?


  1. talraaash
    10.12.2023 19:54

    в fg_color вместо кортежа(light_theme, dark_theme) использовано одно значение для бэкграунда, в итоге в темной теме по умолчанию


    1. IvanZaycev0717 Автор
      10.12.2023 19:54

      да мое упущение, что не тестировал темную тему. Хорошо, что заметили. Сделаю hot fix


    1. IvanZaycev0717 Автор
      10.12.2023 19:54

      Все поправил, всего одна строчка


      1. talraaash
        10.12.2023 19:54

        Спасибо, никогда не имел дел с customtinker, а с ходу не нашел ctk.set_appearance_mode(). Насколько я понимаю, ctk из коробки имеет не плохую поддержку тем и на нем легко имплементировать daark/light темы?


        1. IvanZaycev0717 Автор
          10.12.2023 19:54

          в целом, да. Но при разработке были серьезные проблемы с классами Treeview и Combobox, я не смог добиться нужного поведения через customtkinter. И пришлось эти классы импортировать из обычного tkinter. По поводу dark/light тем - там довольно гибкие возможности, а тем более с тернарными условными операторами Python эти возможности еще более гибкие


  1. nameisBegemot
    10.12.2023 19:54

    Небольшое уточнение

    В мире, очень может быть, Питон джваскрипт и на первом месте. В России номер 1 - это Джава.


  1. ilnurjick
    10.12.2023 19:54

    Какие ещё варианты разработки интерфейса на Python есть, помимо tkinter? Спасибо за customtkinter. Также есть PyQt, QtDesigner для удобства. А есть другие варианты?


    1. IvanZaycev0717 Автор
      10.12.2023 19:54

      вариантов довольно много, просто tkinter - это стандартная библиотека, которая идет вместе с Python. С помощью PyQt я плариую в будущем еще одну свою одну идею реализовать, которая будет поближе к моей профессии.

      Почему надо пользоваться только популярными библиотеками? Я приведу пример из фронэнда: Я захотел написать SPA. Есть прекрасный протестированный вдоль и поперк React, на Stackoverflow есть ответы на все вопросы по этому фреймворку. Но можно это же самое SPA написать на Python библиотека kivy. И это очень плохая идея - там настолько все не логично, мне, например, нужно такое поведение, а его вообще в исходных классах нет.