Python: Составные данные

Пары

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

from hexlet_pair import cons, car, cdr

# Конструктор
pair = cons(8, 7)

car(pair) # 8
cdr(pair) # 7

pair2 = cons(3, pair)

Устроены они достаточно просто и используют структуру данных, которая называется парой. Пар в самом языке Python не существует, мы их реализовали с помощью отдельной библиотеки, и выше можно увидеть пример того, как они используются. Мы подключаем из библиотеки конструктор cons и селекторы car и cdr. Конструктор создаёт пару, а селекторы служат для извлечения из пары первого значения (с помощью car) и второго значения (с помощью cdr). Всё достаточно просто и очень похоже на реализацию точек из прошлого урока.

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

Давайте посмотрим, как представлены наши точки с помощью пар:

def make_point(x, y):
    return cons(x, y)

def get_x(point):
    return car(point)

def get_y(point):
    return cdr(point)

def to_string(point):
    return '({}, {})'.format(get_x(point), get_y(point))

Здесь всё предельно просто: make_point — это функция, которая принимает x и y и вызывает конструктор пары с этими аргументами. То же самое с селекторами: get_x и get_y принимают на вход точку и вызывают с этой точкой car и cdr соответственно.

Можно заметить, что сработало бы даже такое определение:

make_point = cons

get_x = car
get_y = cdr

Здесь всё верно с синтаксической точки зрения и с точки зрения получения конечного результата. Но с таким способом определения есть некоторые проблемы: по сути, когда мы делаем такое присваивание, получается, что make_point и cons являются одним и тем же экземпляром. Кто-то может сказать, что они ссылаются на одну и ту же функцию, но это уже тонкости реализации конкретного языка программирования. На практике это означает, что, запустив построенный таким образом код, вы не увидите вызова функций make_point, get_x или get_y, потому что их фактически не существует. При отладке вы не найдёте этих функций в бэктрейсе. Вы можете захотеть увидеть все вызовы, например, make_point, но вы точно не захотите отслеживать в вашей программе все вызовы cons, которые могут использоваться не только для точек, а вообще для любых библиотек. Поэтому мы не используем такое определение, но о нём нужно знать, чтобы понимать, как в целом всё работает.

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

point1 = make_point(1, 2)
point2 = make_point(10, -2)

segment = make_segment(point1, point2)

start_segment(segment)  # (1, 2)
end_segment(segment)    # (10, -2)

Нам нужно сделать две точки (потому что любой отрезок представлен двумя точками). После этого мы используем конструктор make_segment и передаём туда наши точки, а с помощью селекторов start_segment и end_segment мы получаем точки. Важно, что мы получаем именно точки, потому что это тоже составные данные со своими селекторами, с помощью которых можно получать примитивные значения и производить над ними какие-либо манипуляции при необходимости.


Пары

Обратите внимание на то, что пары неизменяемы. Нельзя просто так взять и изменить пару. Можно только создать новую на основе предыдущей. Поначалу такой способ программирования может показаться необычным и сложным, так как надо перестроить свое мышление. Чем дальше вы будете продвигаться по курсам, тем больше он вам начнет нравиться. Вы увидите, как часто упрощается код и его отладка в отсутствие изменяемости.


Дополнительные материалы

  1. История возникновения cons/car/cdr

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

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

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

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужна профессиональная подписка

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

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

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

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

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг».

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

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Рекомендуемые программы

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

Есть вопрос или хотите участвовать в обсуждении?

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

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг».