Python @classmethod против @staticmethod против функций уровня модуля
3 мая 2023 г.При изучении Python вы неизбежно сталкиваетесь с проблемой выбора между статическими методами (@staticmethod
), методами класса (@classmethod
) и модульными методами.
функции. В этой статье я хотел бы разобраться с этим вопросом.
С технической точки зрения единственная разница между статическими методами и методами класса заключается в том, что метод класса получает класс в качестве первого аргумента.
Рассмотрим простой пример:
class Number:
def __init__(self, value):
self.value = value
@classmethod
def multiply(cls, x, y):
return cls(x*y)
@staticmethod
def divide(x, y):
return Number(x // y)
В этом примере класс Number имеет два метода: метод класса multiply
и статический метод divide
. И мы можем успешно вызвать оба этих метода, и все это будет работать.
>>> n = Number.multiply(1, 2)
>>> n.print()
2
>>> type(n)
<class '__main__.Number'>
>>> n = Number.divide(2, 1)
>>> n.print()
2
>>> type(n)
<class '__main__.Number'>
Но что произойдет, если использовать наследование?
Например:
class Real(Number):
pass
Класс Real
унаследует все методы класса Number
, но когда мы получим доступ к методу divide
, мы получим не совсем то, что могли бы ожидать.
>>> r = Real.multiply(1, 2)
>>> r.print()
2
>>> type(r)
<class '__main__.Real'>
>>> r = Real.divide(2, 1)
>>> r.print()
2
>>>type(r)
<class '__main__.Number'>
Как мы видим, метод divide
вернет экземпляр Number
вместо Real
. Для решения этой проблемы лучше всего использовать @classmethod
-s.
class Number:
def __init__(self, value):
self.value = value
@classmethod
def divide(cls, x, y):
return cls(x // y)
def print(self):
print(self.value)
class Real(Number): pass
>>> r = Real.divide(2, 1)
>>> r.print()
2
>>>type(r)
<class '__main__.Real'>
Так когда же лучше использовать метод класса, статический метод и функцию уровня модуля?
Я считаю, что если функции нужен доступ к классу, то она является методом класса, если ей не нужен доступ ни к классу, ни к экземпляру класса, но логически связана с классом, то она статический метод, в противном случае это функция уровня модуля.
Оригинал