50

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

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 

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

ответ

47

Ваша догадка правильная - вы понимаете как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() 

Об использовании они по инстанциям: есть по крайней мере два основных способа применения для вызова classmethod на примере:

  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), чтобы быть методом на классе (или объекта).

+1

Ницца: Мне нравится, когда ответ разбивается на то, как - почему. Насколько я понял, @classmethod позволяет получить доступ к функции без необходимости в экземпляре. Это именно то, что я искал, спасибо. – marue

+0

@marue Добро пожаловать! – Marcin

+0

Я бы сказал, что методы вызова класса в экземплярах - это плохой стиль кодирования - просто нет причин для этого и может вызвать только путаницу. Но да, это работает (java позволяет то же самое, но выдает предупреждение компиляции при вызове статических методов через экземпляры) – Voo

0

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

+1

(a) Статические методы - это что-то еще; (b) classmethods не разделяются каждым классом. – Marcin

+0

@ Марцин благодарит за то, что дал мне знать мои нечеткие определения и все такое. –