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

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

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

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

Рациональным называют число, которое может быть представлено в виде дроби a/b, где a — это числитель дроби, 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.

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

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

Уровневое проектирование проходит через всю технику построения сложных систем.

Например, при проектировании компьютеров резисторы и транзисторы сочетаются и описываются при помощи языка аналоговых схем. Из них строятся и-, или- элементы и им подобные, которые являются основой языка цифровых схем. Из этих элементов строятся процессоры, шины и системы памяти. Они служат элементами в построении компьютеров при помощи языков, которые подходят для описания компьютерной архитектуры. Компьютеры сочетаются и дают распределенные системы, которые описываются при помощи языков описания сетевых взаимодействий и так далее. (c) SICP

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

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 = add_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
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Python-разработчик
Профессия
с нуля
Разработка веб-приложений на Django
2 февраля 10 месяцев

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

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

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

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