Найти тему
Simple Prog

Разбираемся с методами экземпляра, класса и статическими методами в Python. Часть 1 из 2

Оглавление

В этой статье вы увидите, что именно в Python стоит за методами класса (class methods), статическими методами (static methods) и обычными методами экземпляра (instance methods). Материал большой, поэтому я разделил на две части.

Различие в написании и определении методов

Если вы разовьете интуитивное понимание их различий, то сможете писать объектно-ориентированный программный код Python, который яснее сообщает свой замысел и в конечном счете будет удобнее в сопровождении.

Давайте начнем с написания класса, который содержит простые примеры всех трех типов методов:

Методы экземпляра

Первый метод в MyClass с именем method является обычным методом экземпляра. Это базовый, без наворотов, тип метода, который вы будете использовать бóльшую часть времени. Этот метод принимает один параметр, self, который указывает на экземпляр класса MyClass во время вызова этого метода.

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

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

Методы класса

Давайте сравним это со вторым методом, MyClass.classmethod. Я пометил этот метод декоратором @classmethod, чтобы обозначить его как метод класса.

Вместо параметра self методы класса принимают параметр cls, который указывает на класс, а не на экземпляр во время вызова этого метода.

Поскольку метод класса имеет доступ только к этому аргументу cls, он не может менять состояние экземпляра объекта. Для этого потребовался бы доступ к параметру self. Однако методы класса по-прежнему могут модифицировать состояние класса, которое применимо во всех экземплярах класса.

Статические методы

Третий метод, MyClass.staticmethod, был помечен декоратором @staticmethod, чтобы обозначить его, как статический метод.

Этот тип метода не принимает ни параметр self, ни параметр cls, хотя, конечно же, он может быть сделан так, чтобы принимать произвольное количество других методов.

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

Фото Автора.
Фото Автора.

Посмотрим на них в действии!

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

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

Вот что происходит, когда мы вызываем метод экземпляра:

Этот результат подтверждает, что в данном случае метод экземпляра с именем method имеет доступ к экземпляру объекта (напечатанному как <MyClass instance>) через аргумент self

Во время вызова этого метода Python заменяет аргумент self на объект экземпляра, obj. Чтобы получить тот же самый результат, мы можем проигнорировать синтаксический сахар, предоставляемый синтаксической конструкцией вызова с точкой, obj.method(), и передать объект экземпляра вручную: 

Между прочим, методы экземпляра могут также получать доступ непосредственно к самому классу через атрибут self.__class__. Это делает методы экземпляра мощными с точки зрения ограничений доступа — они могут свободно модифицировать состояние в экземпляре объекта в самом классе. 

Теперь давайте испытаем метод класса: 

Вызов метода classmethod() показал, что у него нет доступа к объекту <MyClass instance>, а есть только к объекту <class MyClass>, представляющему сам класс (в Python все является объектом, даже сами классы). 

Обратите внимание на то, как Python автоматически передает класс в качестве первого аргумента в функцию, когда мы вызываем метод MyClass.classmethod( ). В Python такое поведение запускается вызовом метода через точечный синтаксис (dot syntax). Параметр self в методах экземпляра работает таким же образом. 

Также обратите внимание на то, что обозначение этих параметров как self и cls является всего-навсего согласованным правилом именования. С тем же успехом вы можете назвать их the_object и the_class и получить тот же самый результат. Важно лишь то, что в списке параметров для этого конкретного метода они располагаются первыми. 

Теперь самое время вызвать статический метод

Заметили, как мы вызвали метод staticmethod() объекта и смогли сделать это успешно? Некоторые разработчики удивляются, когда узнают, что статический метод можно вызывать на экземпляре объекта. 

За кадром, когда статический метод вызывается с использованием точечного синтаксиса, Python просто накладывает ограничения доступа, не передавая аргумент self или cls

Этим подтверждается, что статические методы не могут получить доступ ни к состоянию экземпляра объекта, ни к состоянию класса. Они работают как обычные функции, но при этом они принадлежат пространству имен класса (и каждого экземпляра). 

Теперь давайте посмотрим, что произойдет при попытке вызвать эти методы на самом классе, не создавая экземпляр объекта заранее: 

Мы нормально смогли вызвать classmethod() и staticmethod(), а вот попытка вызвать метод экземпляра method() не удалась с исключением TypeError

Такого результата следовало ожидать. На этот раз мы не создали экземпляр объекта и попытались вызвать функцию экземпляра непосредственно на самом шаблоне класса. Иными словами, в Python нет способа заполнить аргумент self, и поэтому данный вызов терпит неудачу с исключением TypeError

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

А пока потренируйтесь в собственном интерпретаторе, исходя из примеров, указанных в статье.

Понравилась статья? Не забудь подписаться и оставить свое мнение в комментариях, обязательно прочту и отвечу.

Читайте также: