Зарегистрируйтесь, чтобы продолжить обучение

Абстракция с помощью функций Python: Функции

Главная причина создания функций — повышение уровня абстракции, а не сокращения дублирования кода, как вы могли бы подумать. Второе является следствием первого. И действительно, вместо того, чтобы реализовывать сортировку самостоятельно в каждом месте, где это требуется, можно воспользоваться функцией sort(), которая прячет реализацию внутри себя и позволяет программисту не отвлекаться на ненужные детали (вид сортировки, код для её выполнения и тд).

Abstraction

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

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

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

Функции высшего порядка выводят абстрагирование с помощью функций на новый уровень. Благодаря делегированию поведения внешнему коду (используя анонимные функции) резко расширяется возможность повторного использования кода в разных ситуациях. И вместо десяти функций для десяти разных участков кода появляется одна функция, которая специфицируется 10 раз разным поведением.

Но не забывайте, что абстракции почти всегда текут.

Пример текущей абстракции

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

Первое решение выглядит примерно так:

def check(number):
    if number % 2 == 0:
        result = "yes"
    else:
        result = "no"
    return result

Оно рабочее, но сама концепция чётности не выделена в свою абстракцию, что, например, затрудняет тестирование и понимание кода. Здесь он простой, но в более сложных случаях догадаться до того, что за операция выполняется — проблематично. Правильно было бы выделить чётность в отдельную функцию, абстракцию.

def is_even(number):
    if number % 2 == 0:
        return "yes"
    else:
        return "no"


def check(number):
    result = is_even(number)
    return result

Посмотрите на код выше внимательно. Всё ли с ним нормально?

На самом деле, этот код даже хуже, чем первая версия, потому что создана неверная абстракция. Понятие чётности числа никак не связано ни с выводом на экран, ни со строчками yes или no. Оно существует в вакууме как математическая концепция и не может знать о том, как её собираются использовать. Я уже не говорю про то, что имя is_even начинается с is, а это значит, что функция — предикат. Такие функции могут возвращать только логическое значение и никак иначе. Правильный вариант выглядит так:

def is_even(number):
    if number % 2 == 0:
        return True
    else:
        return False


def check(number):
    result = "yes" if is_even(number) else "no"
    return result

Еще как один пример - расчет цены со скидкой. Наивным и неправильным подходом будет выполнять все в одной функции:

def calculate(price, discount):
    if discount > 0:
        final = price - (price * discount / 100)
    else:
        final = price
    return f"Final price: {final}"

Здесь запутана логика скидки, форматирования и вывода — три задачи в одной функции.

Правильной же абстракцией будет разделить логику на независимые компоненты:

def apply_discount(price, discount):
    return price - (price * discount / 100)


def format_price(price):
    return f"Final price: {final}"


def calculate(price, discount):
    final = apply_discount(price, discount)
    return format_price(final)

Теперь легко поменять форматирование format_price(), или логику расчёта apply_discount(), не трогая остальной код.

И это самые примитивные варианты создания абстракций. В реальном коде обычно всё значительно сложнее.


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

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

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

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

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

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

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

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

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

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

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff