Объяснение @classmethod и @staticmethod в Python

Spread the love

Перевод: Python’s @classmethod and @staticmethod Explained

Для новичков, изучающих объектно-ориентированное программирование на Python, очень важно хорошо разбираться в таких понятиях как classmethod и staticmethod для написания более оптимизированного и повторно используемого кода.

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

В этой статье мы разберем что это такое и какая между ними разница.

staticmethod в Python

@staticmethod — используется для создания метода, который ничего не знает о классе или экземпляре, через который он был вызван. Он просто получает переданные аргументы, без неявного первого аргумента, и его определение неизменяемо через наследование.

Проще говоря, @staticmethod — это вроде обычной функции, определенной внутри класса, которая не имеет доступа к экземпляру, поэтому ее можно вызывать без создания экземпляра класса.

Синтаксис:

class ClassName:
    @staticmethod
    def method_name(arg1, arg2, ...): ...

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

А теперь посмотрим на пример использования.

class Myclass():
    @staticmethod
    def staticmethod():
        print('static method called')

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

Myclass.staticmethod()

Результат:

static method called

Хотя вызов метода из экземпляра класса тоже возможен.

my_obj = Myclass()
my_obj.staticmethod()

Результат:

static method called

Отлично, но когда полезны статические методы?

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

class Person():
    @staticmethod
    def is_adult(age):
        if age > 18:
            return True
        else:
            return False

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

Person.is_adult(23)

Результат:

True

Classmethod в Python

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

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

Синтаксис:

class Class:
    @classmethod
    def method(cls, arg1, arg2, ...): ... 

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

class MyClass:
    @classmethod
    def classmethod(cls):
        print('Class method called')

Функцию classmethod также можно вызывать без создания экземпляра класса, но его определение следует за подклассом, а не за родительским классом, через наследование.

MyClass.classmethod()

Результат:

Class method called

Когда использовать classmethod?

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

Поэтому, если вы хотите получить доступ к свойству класса в целом, а не к свойству конкретного экземпляра этого класса, используйте classmethod.

class MyClass():
    
    TOTAL_OBJECTS=0
    
    def __init__(self):
        MyClass.TOTAL_OBJECTS = MyClass.TOTAL_OBJECTS+1
       
    @classmethod
    def total_objects(cls):
        print("Total objects: ",cls.TOTAL_OBJECTS)

# Создаем объекты        
my_obj1 = MyClass()
my_obj2 = MyClass()
my_obj3 = MyClass()

# Вызываем classmethod 
MyClass.total_objects()

Результат:

Total objects:  3

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

class MyClass():
    
    TOTAL_OBJECTS=0
    
    def __init__(self):
        MyClass.TOTAL_OBJECTS = MyClass.TOTAL_OBJECTS+1
       
    @classmethod
    def total_objects(cls):
        print("Total objects: ", cls.TOTAL_OBJECTS)

# Создаем объекты родительского класса       
my_obj1 = MyClass()
my_obj2 = MyClass()


# Создаем дочерний класс
class ChildClass(MyClass):
    TOTAL_OBJECTS=0    
    pass

ChildClass.total_objects()

Результат:

Total objects:  0

Заключение

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

Также имейте в виду, что вызов @classmethod включает в себя дополнительное выделение памяти, чего нет при вызове @staticmethod или обычной функции.

Была ли вам полезна эта статья?
[6 / 4]

Spread the love
Подписаться
Уведомление о
guest
5 Комментарий
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Дмитрий
Дмитрий
20 дней назад

То что выделено жирным не понял, можно это как-то развернуть?
Функцию classmethod также можно вызывать без создания экземпляра класса, но его определение следует за подклассом, а не за родительским классом, через наследование.

Editorial Team
Администратор
Editorial Team
20 дней назад
Reply to  Дмитрий

Нет выделение жирным это просто выделение, это не гиперссылка.

Анонимно
Анонимно
17 дней назад
Reply to  Editorial Team

«Развернуть» — это была просьба объяснить подробнее

Дмитрий
Дмитрий
16 дней назад
Reply to  Editorial Team

Я имел ввиду пояснить что значит «но его определение следует за подклассом, а не за родительским классом, через наследование«

Editorial Team
Администратор
Editorial Team
16 дней назад
Reply to  Дмитрий

В оригинальной статье это предложение выглядит так: «@classmethod functions are also callable without instantiating the class, but its definition follows Subclass, not Parent class, via inheritance.» Наверно тут подразумевается что при использование методов класса через @classmethod, вы можете эти методы переопределять в дочерних классах. И вам не нужно использовать механизм наследования. А вообще конечно запутанное предложение.

5
0
Будем рады вашим мыслям, пожалуйста, прокомментируйте.x
()
x