- Статический метод Python
- Как создать статический метод в Python
- 1. Использование функции staticmethod()
- 2. Использование аннотации @staticmethod
- Статический метод и метода класса — сравнение
- Сравнение статического метода и метода экземпляра
- Преимущества
- Статический метод Python
- Пример №1
- Пример №2
- Пример №3
- Подведем итоги
- Объяснение @classmethod и @staticmethod в Python
- staticmethod в Python
- Classmethod в Python
- Заключение
Статический метод Python
Статические методы позволяют разделить служебные методы на отдельные подмодули.
Допустим, у нас есть модуль Python для служебных методов для строк, списков и кортежей.
Мы можем создавать статические методы в отдельных классах для лучшего понимания и простоты использования.
class ListUtils: @staticmethod def reverse(l): pass @staticmethod def clear(l): pass class StringUtils: @staticmethod def reverse(l): pass @staticmethod def upper(l): pass class TupleUtils: @staticmethod def reverse(t): pass @staticmethod def shuffle(t): pass
Если нам нужно перевернуть список, мы ListUtils.reverse() метод ListUtils.reverse() . Если нам нужно перетасовать элементы кортежа, мы TupleUtils.shuffle() статический метод TupleUtils.shuffle() .
Как создать статический метод в Python
1. Использование функции staticmethod()
Staticmethod() полезен, когда вы хотите создать статический метод, определенный в классе. Обратите внимание, что у метода не должно быть аргумента self.
class StringUtils: def to_uppercase(s): return str(s).upper() StringUtils.upper = staticmethod(StringUtils.to_uppercase) print(StringUtils.upper('Python')) # PYTHON
Если мы попытаемся вызвать метод to_uppercase() из объекта StringUtils, он вызовет ошибку, поскольку «метод принимает 1 позиционный аргумент, но было дано 2».
su = StringUtils() try: print(su.to_uppercase('Python')) except TypeError as te: print(te) # Output # to_uppercase() takes 1 positional argument but 2 were given
Однако мы можем вызвать метод to_uppercase() из ссылки на класс.
print(StringUtils.to_uppercase('Python')) # PYTHON
2. Использование аннотации @staticmethod
Это рекомендуемый способ создания статического метода. Нам просто нужно аннотировать метод декоратором @staticmethod.
class MathUtils: @staticmethod def multiply(a, b): return a * b print(MathUtils.multiply(10, 5)) # 50
Статический метод и метода класса — сравнение
- Метод класса Python может получить доступ к переменным класса, но статический метод не может получить доступ к переменным класса.
- Метод класса требует, чтобы первый формальный параметр был привязан к классу. Статический метод может присутствовать без каких-либо параметров.
- Мы используем @classmethod для создания методов класса. Мы используем @staticmethod для создания статических методов.
class Test: x = 10 @classmethod def foo(cls): print(cls.x) @staticmethod def bar(): # Unresolved reference error for class variable x # print(x) pass
Сравнение статического метода и метода экземпляра
- Метод экземпляра в классе может обращаться как к переменным экземпляра, так и к переменным класса. Статический не может получить доступ к переменным класса или переменным экземпляра.
- Нам нужна «собственная переменная» в качестве формального параметра для метода экземпляра. В статическом такого ограничения нет.
- Мы используем декоратор @staticmethod. Нам не нужны декораторы для создания функции экземпляра.
class Test: x = 10 def func(self): print(type(self)) print(self.x)
Преимущества
Статические методы полезны для группировки служебных методов внутри границ класса. В остальном это просто обычная функция в скрипте Python.
Статический метод Python
Статический метод в Python — это метод, который связан с классом, а не с его экземплярами. Чтобы быть вызванным, он не требует создания экземпляра класса и не имеет доступа к экземпляру. Статические методы в Python объявляются с использованием декоратора @staticmethod . Этот декоратор указывает интерпретатору Python, что метод является статическим, и следует вызывать его через класс, а не через экземпляр класса.
Таким образом, статические методы в Python могут использоваться для выполнения операций, не требующих доступа к экземпляру класса или его атрибутам, то есть, по сути, они являются вспомогательными функциями. Чтобы было понятнее, о чём речь, перейдем сразу к практике.
Пример №1
Представим, что у нас есть класс MathUtils , который содержит статический метод для вычисления факториала:
class MathUtils:
@staticmethod
def factorial(n):
if n == 0:
return 1
else:
return n * MathUtils.factorial(n-1)
print(MathUtils.factorial(5))
120
Получили факториал 5, то есть 120. Здесь статический метод factorial не использует никакие атрибуты экземпляра класса, а только входной аргумент n . И мы вызвали его, используя синтаксис MathUtils.factorial(n) и не создавая экземпляр класса MathUtils .
Далее отметим, что статические методы в Python могут использоваться не только в классах, но также в модулях и пакетах. Если вы определяете функцию в модуле и не хотите, чтобы она была связана с экземпляром класса или модулем, вы можете использовать декоратор @staticmethod для объявления этой функции как статической.
Пример №2
Допустим, у нас есть модуль StringUtils , содержащий статический метод для проверки, является ли строка палиндромом. Пишем такой код:
def is_palindrome(string):
return string == string[::-1]
Здесь функция is_palindrome не связана с каким-либо экземпляром класса или объектом модуля, поэтому мы можем использовать декоратор @staticmethod для объявления ее как статической. Для этого расширим наш код таким образом:
class StringUtils:
@staticmethod
def is_palindrome(string):
return string == string[::-1]
Далее введем для проверки:
print(StringUtils.is_palindrome("топот"))
True
print(StringUtils.is_palindrome("топор"))
False
Всё верно, первое слово является палиндромом, поэтому интерпретатор вывел True , а второе нет, и мы получили False .
Таким образом, мы можем вызвать метод is_palindrome через класс StringUtils , используя синтаксис StringUtils.is_palindrome(string) вместо того, чтобы импортировать функцию is_palindrome и вызывать ее напрямую.
Еще одно важное отличие статических методов от методов экземпляров класса в Python заключается в том, что статические методы не могут изменять состояние экземпляра. Это означает, что они не могут изменять значения атрибутов, что логично, так как они не имеют доступа к экземпляру. Если вы хотите изменить состояние экземпляра класса, вам нужно использовать методы экземпляров.
Пример №3
Рассмотрим еще один пример. Допустим, у нас есть класс Person , имеющий атрибут age и статический метод is_adult , проверяющий значение на соответствие возрасту совершеннолетия:
class Person:
def __init__(self, age):
self.age = age
@staticmethod
def is_adult(age):
return age >= 18
Далее давайте создадим переменную age со значением 21, вызовем статический метод is_adult из класса Person с этим значением и сохраним его результат в переменную is_adult , вот так:
age = 21
is_adult = Person.is_adult(age)
Теперь для проверки давайте введем:
Поскольку возраст соответствует заданному в статическом методе условию, мы получили True . В примере выше статический метод is_adult принимает аргумент age , но не имеет доступа к атрибуту age экземпляра класса Person , выступая в качестве вспомогательной функции.
Подведем итоги
В завершение отметим, что статические методы улучшают читабельность кода и дают возможность повторно использовать его. А еще они удобнее, если сравнивать их со стандартными функциями Python. Удобство статических методов в том, что они не требуют отдельного импорта, как это нужно делать для функций. Таким образом, использование статических методов класса Python может существенно упростить код и работу с ним. И, как вы наверняка убедились на примерах выше, освоить их довольно просто.
Объяснение @classmethod и @staticmethod в Python
Для новичков, изучающих объектно-ориентированное программирование на 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')
Как мы уже говорили, мы можем получить доступ к статическому методу класса без создания экземпляра.
Хотя вызов метода из экземпляра класса тоже возможен.
my_obj = Myclass() my_obj.staticmethod()
Отлично, но когда полезны статические методы?
Статический метод помогает в достижении инкапсуляции в классе, поскольку он не знает о состоянии текущего экземпляра. Кроме того, статические методы делают код более читабельным и повторно используемым, а также более удобным для импорта по сравнению с обычными функциями, поскольку каждую функцию не нужно отдельно импортировать.
class Person(): @staticmethod def is_adult(age): if age > 18: return True else: return False
В приведенном выше примере мы можем проверить, является ли человек взрослым, без инициирование создания экземпляра.
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 также можно вызывать без создания экземпляра класса, но его определение следует за подклассом, а не за родительским классом, через наследование.
Когда использовать 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 и вызовем метод класса из дочернего класса, он вернет общее количество объектов для дочернего класса.
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()
Заключение
@classmethod используется в суперклассе для определения того, как метод должен вести себя, когда он вызывается разными дочерними классами. В то время как @staticmethod используется, когда мы хотим вернуть одно и то же, независимо от вызываемого дочернего класса.
Также имейте в виду, что вызов @classmethod включает в себя дополнительное выделение памяти, чего нет при вызове @staticmethod или обычной функции.