Python

Объяснение @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 или обычной функции.

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

Spread the love
Editorial Team

View Comments

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

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

      • "Развернуть" - это была просьба объяснить подробнее

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

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

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

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

      • Когда знаний достаточно и разбираться не надо - все и так понятно. Статья местамиj полезная, но хотелось бы попроще. Заключение вообще ни о чем - если нет дочерних классов .@classmethod и @staticmethodни как нельзя использовать?

    • Отличная статья и все понятно! Хотя может у меня еще недостаточно знаний, для того чтобы сравнивать (оценивать), но эта статья мне была понятна

    • Ерунду вы пишите. Всё очень понятно. Как бы рассчитано, что уже есть базовые понятия об классах, экземплярах и в целом принципах ООП

      • Цитата из статьи "Для новичков, изучающих объектно-ориентированное программирование на Python, очень важно"

      • Надо было сравнение предоставить. В каких моментах один тип будет работать, а другой нет. И где один по одному сработает, а другой нет. И разжевать желательно, раз для новичков :-)

        • При правильно указанных аргументах: не указывать self в @staticmethod и использовать cls в @classmethod все будет работать. Разницы не заметите.
          Разница как раз кроется в деталях надо понимать что cls это ссылка на класс. Соответственно в дочерних классах можно влиять непосредственно на родительский класс.

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

12 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

12 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

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

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

2 года ago