В прошлой части мы с вами разобрались, в чем разница между методами класса, экземпляра и статическими методами. Сегодня попрактикуемся на примере с пиццей. Почему бы и нет)
Итак, в своих примерах я буду исходить из элементарного класса Pizza:
Фабрики аппетитной пиццы с @classmethod
Если вы сталкивались с пиццей в реальном мире, то вы знаете, что существует много видов аппетитной пиццы:
Pizza([ 'моцарелла', 'помидоры' ])
Pizza(['моцарелла', 'помидоры', 'ветчина', 'грибы'])
Pizza([ 'моцарелла'] * 4)
Итальянцы придумали свою классификацию пицц несколько веков назад, и поэтому все эти типы восхитительных пицц имеют свои собственные имена. Будет хорошо, если мы этим воспользуемся и дадим пользователям нашего класса Pizza более оптимальный интерфейс для создания объектов-пицц, которые они хотят.
Хороший и очевидный способ это сделать — использовать методы класса в качестве фабричных функций для различных видов пицц, которые мы можем создать:
Обратите внимание на то, как я использую аргумент cls в фабричных методах margherita и prosciutto вместо вызова конструктора Pizza непосредственно.
Вы можете использовать эту идиому, чтобы следовать принципу «Не повторяйся» (DRY). Если в какой-то момент мы решим этот класс переименовать, нам не нужно будет помнить об обновлении имени конструктора во всех фабричных функциях.
Итак, что же мы можем сделать с этими фабричными методами? Давайте их испытаем:
Как видите, фабричные функции можно использовать для создания новых объектов Pizza, которые сконфигурированы именно так, как мы хотим. Внутри они все используют одинаковый конструктор __init__ и просто обеспечивают краткую форму для запоминания самых разнообразных ингредиентов.
Еще один способ взглянуть на это использование методов класса — понять, что они позволяют определять для своих классов альтернативные конструкторы.
Python допускает всего один метод __init__ в классе. Использование методов класса позволяет добавлять столько альтернативных конструкторов, сколько потребуется. Это может сделать интерфейс ваших классов (до известной степени) самодокументирующим и упростит их использование.
Когда использовать статические методы
Здесь уже сложнее найти хороший пример, и знаете что? Я просто продолжу растягивать аналогию пиццы, делая ее все тоньше и тоньше...(ам!)
И вот что я придумал:
Итак, Что же я тут поменял? Прежде всего, я изменил конструктор и метод __repr__, и теперь они принимают дополнительный аргумент radius.
Я также добавил метод экземпляра area(), который вычисляет и возвращает площадь пиццы. Это также будет подходящей кандидатурой для @property... но постойте, это же просто игрушечный пример.
Вместо того чтобы вычислять площадь непосредственно внутри метода area() при помощи общеизвестной формулы площади круга, я вынес это вычисление в отдельный статический метод circle_area().
Давайте его испытаем!
Несомненно, этот пример по-прежнему довольно упрощенный, но он поможет объяснить некоторые преимущества, предоставляемые статическими методами.
Как мы узнали, статические методы не могут получать доступ к состоянию класса или экземпляра, потому что они не принимают аргумент cls или self. Этот факт является большим ограничением — но он также является замечательным сигналом, который обозначает, что тот или иной метод независим от всего остального вокруг него.
Из примера выше совершенно ясно, что circle_area() никак не может модифицировать класс или экземпляр класса. (Разумеется, это ограничение всегда можно обойти при помощи глобальной переменной, но это уже к делу не относится.)
Итак, почему же это полезно?
Обозначение метода как статического не просто подсказка, что этот метод не сможет модифицировать состояние экземпляра или класса. Но, как вы убедились, это ограничение также подкрепляется во время выполнения программы Python.
Ключевые выводы
- Методы экземпляра нуждаются в экземпляре класса и могут получать доступ к экземпляру через параметр self.
- Методы класса не нуждаются в экземпляре класса. Они не могут получать доступ к экземпляру, но у них есть доступ непосредственно к самому класса через cls.
- Статические методы не имеют доступа ни к cls, ни к self. Они работают как обычные функции, но принадлежат пространству имен класса.
- Статические методы и методы класса сообщают и (до известной степени) подкрепляют замысел разработчика в отношении конструкции класса. Это может обладать определенными преимуществами в сопровождении кода.
Понравилась статья? Не забудь подписаться и оставить свое мнение в комментариях, обязательно прочту и отвечу.
Читайте также: