Объяснение @classmethod и @staticmethod в Python
Перевод: 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 или обычной функции.
То что выделено жирным не понял, можно это как-то развернуть?
Функцию classmethod также можно вызывать без создания экземпляра класса, но его определение следует за подклассом, а не за родительским классом, через наследование.
Нет выделение жирным это просто выделение, это не гиперссылка.
«Развернуть» — это была просьба объяснить подробнее
Я имел ввиду пояснить что значит «но его определение следует за подклассом, а не за родительским классом, через наследование«
В оригинальной статье это предложение выглядит так: «@classmethod functions are also callable without instantiating the class, but its definition follows Subclass, not Parent class, via inheritance.» Наверно тут подразумевается что при использование методов класса через @classmethod, вы можете эти методы переопределять в дочерних классах. И вам не нужно использовать механизм наследования. А вообще конечно запутанное предложение.
Мусор а не статья, зашел сюда что бы освежить знания, более сложных и не явных формулировок еще поискать надо. Любой новичок что зайдет на эту статью не поймет ничего.