Когда я должен использовать @classmethod и когда метод def (self)?

При интеграции приложения Django, которое я раньше не использовал, я нашел два разных способа определения функций в классах. Автор, кажется, использует их оба преднамеренно. Первый, который я сам часто использую:

class Dummy(object):

    def some_function(self,*args,**kwargs):
        do something here
        self is the class instance

Другой - тот, который я не использую, в основном потому, что я не понимаю, когда его использовать и для чего:

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        do something here
        cls refers to what?

В документации по Python classmethod декоратор объясняется этим предложением:

Метод класса получает класс как неявный первый аргумент, так же, как метод экземпляра получает экземпляр.

Так что я думаю cls относится к Dummy сам (class, а не экземпляр). Я не совсем понимаю, почему это существует, потому что я всегда мог сделать это:

type(self).do_something_with_the_class

Это только для ясности, или я упустил самую важную часть: жуткие и захватывающие вещи, которые нельзя было бы сделать без этого?

4 ответа

Решение

Ваше предположение верно - вы понимаете, как classmethodс работой.

Почему эти методы могут быть вызваны как в экземпляре, так и в классе (в обоих случаях объект класса будет передан в качестве первого аргумента):

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        print cls

#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()

Об их использовании в экземплярах: существует как минимум два основных способа вызова метода класса в экземпляре:

  1. self.some_function() назову версию some_function на фактический тип selfвместо того, чтобы класс, в котором происходит этот вызов (и не будет нуждаться во внимании, если класс будет переименован); а также
  2. В случаях, когда some_function необходимо реализовать некоторый протокол, но полезно вызывать только объект класса.

Разница сstaticmethod: Есть еще один способ определения методов, которые не обращаются к данным экземпляра, называемый staticmethod, Это создает метод, который вообще не получает неявный первый аргумент; соответственно не будет передано никакой информации об экземпляре или классе, в котором он был вызван.

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)

In [7]: Foo.some_static(1)
Out[7]: 2

In [8]: Foo().some_static(1)
Out[8]: 2

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)

In [10]: Bar.some_static(1)
Out[10]: 2

In [11]: Bar().some_static(1)
Out[11]: 2

Основное использование, которое я нашел для этого, состоит в том, чтобы адаптировать существующую функцию (которая не ожидает получения self) быть методом класса (или объекта).

Одним из наиболее распространенных применений в Python являются фабрики, которые являются одним из наиболее эффективных методов создания объекта. Потому что classmethods, как и s, не нуждаются в создании экземпляра класса. (Но тогда, если мы используем staticmethod, нам пришлось бы жестко закодировать имя класса экземпляра в функции)

Этот блог отлично объясняет это:https://iscinumpy.gitlab.io/post/factory-classmethods-in-python/

В принципе, вы должны использовать @classmethod, когда понимаете, что определение метода не будет изменено или отменено.

Дополнительно: теоретически методы класса быстрее, чем методы объектов, потому что не требуют создания экземпляров и требуют меньше памяти.

Если вы добавите декоратор @classmethod, это означает, что вы собираетесь сделать этот метод статическим методом Java или C++. (я думаю, статический метод - это общий термин ;)) В Python также есть @staticmethod. Разница между classmethod и staticmethod заключается в том, можете ли вы получить доступ к классу или статической переменной, используя аргумент или само имя класса.

class TestMethod(object):
    cls_var = 1
    @classmethod
    def class_method(cls):
        cls.cls_var += 1
        print cls.cls_var

    @staticmethod
    def static_method():
        TestMethod.cls_var += 1
        print TestMethod.cls_var
#call each method from class itself.
TestMethod.class_method()
TestMethod.static_method()

#construct instances
testMethodInst1 = TestMethod()    
testMethodInst2 = TestMethod()   

#call each method from instances
testMethodInst1.class_method()
testMethodInst2.static_method()

все эти классы увеличивают cls.cls_var на 1 и печатают его.

И все классы, использующие одно и то же имя в одной и той же области видимости или экземплярах, созданных с помощью этих классов, будут совместно использовать эти методы. Есть только один TestMethod.cls_var, а также есть только один TestMethod.class_method(), TestMethod.static_method()

И важный вопрос. зачем нужен этот метод.

classmethod или staticmethod полезны, когда вы создаете этот класс как фабрику или когда вам нужно инициализировать ваш класс только один раз. например, открыть файл один раз и использовать метод подачи, чтобы прочитать файл построчно.

Другие вопросы по тегам