Когда следует использовать метод @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 

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

Ваша догадка правильная – вы понимаете, как работает classmethod .

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

 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() 

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

  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 ) как метод для класса (или объекта).

Если вы добавите декоратор @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 полезен, когда вы делаете этот класс как фабрику или когда вы должны инициализировать свой класс только один раз. как открытый файл один раз, и используя метод подачи для чтения файла по строкам.