Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Уровневое проектирование Python: Абстракция с помощью данных

В этом уроке мы рассмотрим еще одну систему — рациональные числа и операции над ними, а также научимся видеть барьеры абстракции и выделять слои.

Рациональное число

Рациональным называют число, которое может быть представлено в виде дроби a/b, где а — это числитель дроби, b — знаменатель дроби. Причем b не должно быть нулем, так как делить на нуль нельзя.

Рациональные числа в Python не поддерживаются, поэтому абстракцию для них создадим самостоятельно. Нам понадобятся конструктор и селекторы:

# Создали рациональное число "одна вторая"
num = make_rational(1, 2)
numer = get_numer(num)
# 1
denom = get_denom(num)
# 2

С помощью трех функций мы определили рациональное число. Конструктор собирает его из частей, селекторы позволяют извлечь каждую часть. Чем при этом является num с точки зрения языка — не важно. Это может быть функция, список или словарь. Во внутренней реализации можно использовать даже строки:

def make_rational(numer, denom):
    return f"{numer}/{denom}"

def get_numer(rational):
    numer, _ = rational.split('/')
    return numer

def get_denom(rational):
    _, denom = rational.split('/')
    return denom

make_rational(10, 3)
# "10/3"

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

Для рациональных чисел базовыми операциями можно считать арифметические, например, сложение, вычитание или умножение. Умножение рациональных чисел — самая простая операция. Для ее выполнения нужно перемножить числители и знаменатели:

3/4 * 4/5 = (3 * 4)/(4 * 5) = 12/20

Если предположить, что реальная структура рационального числа выглядит так: {"numer": 2, "denom": 3}, то решение может быть таким:

def multiply_rational(rational1, rational2):
    return {
        "numer": rational1["numer"] * rational2["numer"],
        "denom": rational1["denom"] * rational2["denom"],
    }

С точки зрения вызывающего кода абстракция сохранена. На вход в multiply_rational подаются рациональные числа, на выходе — рациональное число. Но внутри абстракции нет, так как обращение с рациональными числами строится на основе знания их устройства.

Чтобы изменить внутреннюю реализацию рациональных чисел, придется переписать все операции, которые работают с рациональными числами напрямую — то есть без селекторов или конструктора. Данный код нарушает принцип одного уровня абстракции — single layer abstraction.

Уровневое проектирование

При разработке сложных систем используется подход — уровневое проектирование. В его случае системе придается структура с помощью последовательных уровней. Каждый из уровней строится путем комбинации частей, которые на данном уровне рассматриваются как элементарные. Части, которые строятся на каждом уровне, работают как элементарные на следующем:

levels.png

Уровневое проектирование проходит через всю технику построения сложных систем. Например, в разработке программного обеспечения уровневое проектирование может начинаться с создания низкоуровневых функций и библиотек, которые решают конкретные задачи. К таким задачам могут относиться обработка данных, сетевое взаимодействие или графический интерфейс.

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

Посмотрим на пример кода:

def multiply_rational(rational1, rational2):
    return make_rational(
        get_numer(rational1) * get_numer(rational2),
        get_denom(rational1) * get_denom(rational2),
    )

Здесь базовым уровнем являются типы, которые встроены в сам язык: числа и словарь. На их основе сформирован уровень для представления рациональных чисел: make_rational, get_denom, get_numer. Затем — уровень, на котором реализованы арифметические операции над рациональными числами: сложение, вычитание, умножение и так далее.

Речь идет про реализацию самих уровней. Например, операция сложения полностью опирается на конструктор и селекторы, но ничего не знает и не может знать про внутреннее устройство самих рациональных чисел. С другой стороны, это не значит, что в одном месте не могут появиться функции из разных уровней. Это нормально во многих случаях. Например:

def f(rational1, rational2):
    rational3 = multiply_rational(rational1, rational2)
    denom = get_denom(rational3)
    numer = get_numer(rational3)
    print(f"Denom: {denom}")
    print(f"Numer: {numer}")

Выводы

В этом уроке мы рассмотрели еще одну систему — рациональные числа и операции над ними. Так как в Python рациональные числа не поддерживаются, нам предстояло самостоятельно создать для них абстракцию.

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


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

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

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Обучитесь разработке бэкенда сайтов и веб-приложений — серверной части, которая отвечает за логику и базы данных
10 месяцев
с нуля
Старт 28 ноября

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»