Python @classmethod против @staticmethod против функций уровня модуля

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'>

Так когда же лучше использовать метод класса, статический метод и функцию уровня модуля?

Я считаю, что если функции нужен доступ к классу, то она является методом класса, если ей не нужен доступ ни к классу, ни к экземпляру класса, но логически связана с классом, то она статический метод, в противном случае это функция уровня модуля.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE