На этом шаге мы разберем еще один пример.
Если вы сталкивались с пиццей в реальном мире, то вы знаете, что существует много видов аппетитной пиццы:
Pizza(['моцарелла', 'помидоры']) Pizza(['моцарелла', 'помидоры', 'ветчина', 'грибы']) Pizza(['моцарелла'] * 4)
Итальянцы придумали свою классификацию пицц несколько веков назад, и поэтому все эти типы восхитительных пицц имеют свои собственные имена. Будет хорошо, если мы этим воспользуемся и дадим пользователям нашего класса Pizza более оптимальный интерфейс для создания объектов-пицц, которые они хотят.
Хороший и очевидный способ это сделать - использовать методы класса в качестве фабричных функций для различных видов пицц, которые мы можем создать:
См. Википедию: «Фабрика (объектно-ориентированное программирование)»: https://en.wikipedia.org/wiki/Factory_(object-oriented_programming) и
https://ru.wikipedia.org/wiki/Абстрактная_фабрика_(шаблон_проектирования)
>>> class Pizza: def __init__(self, ingredients): self.ingredients = ingredients def __repr__(self): return f'Pizza({self.ingredients!r})' @classmethod def margherita(cls): return cls(['моцарелла', 'помидоры']) @classmethod def prosciutto(cls): return cls(['моцарелла', 'помидоры', 'ветчина'])
Обратите внимание на то, как используется аргумент cls в фабричных методах margherita() и prosciutto() вместо вызова конструктора Pizza непосредственно.
Вы можете использовать эту идиому, чтобы следовать принципу "Не повторяйся" (DRY). Если в какой-то момент мы решим этот класс переименовать, нам не нужно будет помнить об обновлении имени конструктора во всех фабричных функциях.
Итак, что же мы можем сделать с этими фабричными методами? Давайте их испытаем:
>>> Pizza.margherita() Pizza(['моцарелла', 'помидоры']) >>> Pizza.prosciutto() Pizza(['моцарелла', 'помидоры', 'ветчина'])
Как видите, фабричные функции можно использовать для создания новых объектов Pizza, которые сконфигурированы именно так, как мы хотим. Внутри они все используют одинаковый конструктор __init__() и просто обеспечивают краткую форму для запоминания самых разнообразных ингредиентов.
Еще один способ взглянуть на это использование методов класса - понять, что они позволяют определять для своих классов альтернативные конструкторы.
Python допускает всего один метод __init__() в классе. Использование методов класса позволяет добавлять столько альтернативных конструкторов, сколько потребуется. Это может сделать интерфейс ваших классов (до известной степени) самодокументирующим и упростит их использование.
На следующем шаге мы рассмотрим, когда использовать статические методы.