Когда следует использовать метод @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
Это просто для ясности, или я пропустил самую важную роль: жуткий и увлекательный, что нельзя было сделать без него?
Ответы
Ответ 1
Ваша догадка правильная - вы понимаете, как работает 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 в экземпляре:
-
self.some_function()
будет вызывать версию some_function
для фактического типа self
, а не класса, в котором этот вызов появляется (и не будет нуждаться в внимании, если класс будет переименован); и
- В случаях, когда
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
) как метод для класса (или объекта).
Ответ 2
Если вы добавите декоратор @classmethod, значит, вы собираетесь сделать этот метод статическим методом java или С++. (статический метод общий термин Я думаю ;))
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 полезен, если вы создаете этот класс как factory
или когда вы должны инициализировать свой класс только один раз. как открытый файл один раз, и используя метод подачи для чтения файла по строкам.