В чем разница между @staticmethod и @classmethod?
-
02-07-2019 - |
Вопрос
В чем разница между функцией, украшенной @staticmethod
и один украшен @classmethod
?
Решение
Возможно, небольшой пример кода поможет:Обратите внимание на разницу в сигнатурах вызовов foo
, class_foo
и static_foo
:
class A(object):
def foo(self, x):
print "executing foo(%s, %s)" % (self, x)
@classmethod
def class_foo(cls, x):
print "executing class_foo(%s, %s)" % (cls, x)
@staticmethod
def static_foo(x):
print "executing static_foo(%s)" % x
a = A()
Ниже приведен обычный способ вызова метода экземпляром объекта.Экземпляр объекта, a
, неявно передается в качестве первого аргумента.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
С методами класса, класс экземпляра объекта неявно передается в качестве первого аргумента вместо self
.
a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Вы также можете позвонить class_foo
используя класс.На самом деле, если вы определяете что -то как классное матод, это, вероятно, потому, что вы намереваетесь назвать это из класса, а не из экземпляра класса. A.foo(1)
вызвало бы ошибку TypeError, но A.class_foo(1)
работает отлично:
A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Одно из применений, которое люди нашли для методов класса, — это создание наследуемые альтернативные конструкторы.
Со статическими методами, ни один self
(экземпляр объекта), ни cls
(класс) неявно передается в качестве первого аргумента.Они ведут себя как простые функции, за исключением того, что их можно вызывать из экземпляра или класса:
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
Статические методы используются для группировки функций, которые имеют некоторую логическую связь с классом.
foo
это просто функция, но когда вы вызываете a.foo
Вы не просто получаете функцию, вы получаете «частично примененную» версию функции с экземпляром объекта a
привязан как первый аргумент функции. foo
ожидает 2 аргумента, в то время как a.foo
ожидает только 1 аргумент.
a
связан с foo
.Вот что подразумевается под термином «связанный» ниже:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
С a.class_foo
, a
не обязан class_foo
, скорее класс A
связан с class_foo
.
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Здесь со статическим методом, хотя это метод, a.static_foo
Просто возвращает хорошую функцию без аргументов. static_foo
ожидает 1 аргумент, иa.static_foo
также ожидает 1 аргумент.
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
И, конечно же, то же самое происходит, когда вы звоните static_foo
с классом A
вместо.
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
Другие советы
А статический метод — это метод, который ничего не знает о классе или экземпляре, из которого он был вызван.Он просто получает переданные аргументы, без неявного первого аргумента.В Python это практически бесполезно — вы можете просто использовать функцию модуля вместо статического метода.
А метод класса, С другой стороны, это метод, которому в качестве первого аргумента передается класс, из которого он был вызван, или класс экземпляра, из которого он был вызван.Это полезно, если вы хотите, чтобы метод был фабрикой для класса:поскольку он получает фактический класс, который был вызван, в качестве первого аргумента, вы всегда можете создать экземпляр нужного класса, даже если задействованы подклассы.Посмотрите, например, как dict.fromkeys()
, метод класса, возвращает экземпляр подкласса при вызове в подклассе:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
По сути @classmethod
создает метод, первым аргументом которого является класс, из которого он вызван (а не экземпляр класса), @staticmethod
не имеет неявных аргументов.
Официальная документация Python:
Метод класса получает класс как неявный первый аргумент, как метод экземпляра получает экземпляр.Чтобы объявить метод класса, используйте эту идиому:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
А
@classmethod
форма - это функция декоратор - См. Описание определений функций в Определения функций для получения подробной информации.Это можно назвать либо в классе (например
C.f()
) или в случае (напримерC().f()
).Экземпляр игнорируется, за исключением его класса.Если метод класса требуется для полученного класса, полученный объект класса передается как подразумеваемый первый аргумент.Методы класса отличаются от статических методов C ++ или Java.Если вы хотите, посмотрите
staticmethod()
в этой секции.
Статический метод не получает неявный первый аргумент.Чтобы объявить статический метод, используйте эту идиому:
class C: @staticmethod def f(arg1, arg2, ...): ...
А
@staticmethod
форма - это функция декоратор - См. Описание определений функций в Определения функций для получения подробной информации.Это можно назвать либо в классе (например
C.f()
) или в случае (напримерC().f()
).Экземпляр игнорируется, за исключением его класса.Статические методы в Python аналогичны тем, которые обнаружены в Java или C ++.Для более продвинутой концепции см.
classmethod()
в этой секции.
Здесь это короткая статья по этому вопросу
Функция @staticmethod — это не что иное, как функция, определенная внутри класса.Его можно вызвать без предварительного создания экземпляра класса.Его определение неизменно посредством наследования.
Функцию @classmethod также можно вызвать без создания экземпляра класса, но ее определение следует за подклассом, а не родительским классом, посредством наследования.Это потому, что первым аргументом функции @classmethod всегда должен быть cls (класс).
Чтобы решить, использовать ли @staticmethod или @classmethod вам нужно заглянуть внутрь своего метода. Если ваш метод обращается к другим переменным/методам вашего класса, используйте @classmethod..С другой стороны, если ваш метод не затрагивает другие части класса, используйте @staticmethod.
class Apple:
_counter = 0
@staticmethod
def about_apple():
print('Apple is good for you.')
# note you can still access other member of the class
# but you have to use the class instance
# which is not very nice, because you have repeat yourself
#
# For example:
# @staticmethod
# print('Number of apples have been juiced: %s' % Apple._counter)
#
# @classmethod
# print('Number of apples have been juiced: %s' % cls._counter)
#
# @classmethod is especially useful when you move your function to other class,
# you don't have to rename the class reference
@classmethod
def make_apple_juice(cls, number_of_apples):
print('Make juice:')
for i in range(number_of_apples):
cls._juice_this(i)
@classmethod
def _juice_this(cls, apple):
print('Juicing %d...' % apple)
cls._counter += 1
В чем разница между @staticmethod и @classmethod в Python?
Возможно, вы видели код Python, подобный этому псевдокоду, который демонстрирует сигнатуры различных типов методов и предоставляет строку документации для объяснения каждого из них:
class Foo(object):
def a_normal_instance_method(self, arg_1, kwarg_2=None):
'''
Return a value that is a function of the instance with its
attributes, and other arguments such as arg_1 and kwarg2
'''
@staticmethod
def a_static_method(arg_0):
'''
Return a value that is a function of arg_0. It does not know the
instance or class it is called from.
'''
@classmethod
def a_class_method(cls, arg1):
'''
Return a value that is a function of the class and other arguments.
respects subclassing, it is called with the class it is called from.
'''
Обычный метод экземпляра
Сначала я объясню a_normal_instance_method
.Это именно называется "метод экземпляра".Когда используется метод экземпляра, он используется как частичная функция (в отличие от полной функции, определенной для всех значений при просмотре в исходном коде), то есть при использовании первый из аргументов предопределен как экземпляр метода экземпляра. объект со всеми его заданными атрибутами.К нему привязан экземпляр объекта, и его необходимо вызывать из экземпляра объекта.Обычно он обращается к различным атрибутам экземпляра.
Например, это экземпляр строки:
', '
если мы используем метод экземпляра, join
На этой строке, чтобы присоединиться к другому итератированию, он, очевидно, является функцией экземпляра, в дополнение к функции итерабильного списка, ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Связанные методы
Методы экземпляра можно привязать с помощью точечного поиска для последующего использования.
Например, это связывает str.join
метод к ':'
пример:
>>> join_with_colons = ':'.join
А позже мы сможем использовать это как функцию, к которой уже привязан первый аргумент.Таким образом, это работает как частичная функция в экземпляре:
>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'
Статический метод
Статический метод делает нет примите этот пример в качестве аргумента.
Это очень похоже на функцию уровня модуля.
Однако функция уровня модуля должна находиться в модуле и быть специально импортирована в другие места, где она используется.
Однако, если он прикреплен к объекту, он также будет удобно следовать за объектом посредством импорта и наследования.
Пример статического метода: str.maketrans
, переехал из string
модуль на Python 3.Это делает таблицу перевода пригодной для использования str.translate
.Это кажется довольно глупым при использовании из экземпляра строки, как показано ниже, но импорт функции из string
модуль довольно неуклюж, и приятно иметь возможность вызывать его из класса, как в str.maketrans
# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
В Python 2 вам придется импортировать эту функцию из все менее полезного строкового модуля:
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Метод класса
Метод класса аналогичен методу экземпляра тем, что он принимает неявный первый аргумент, но вместо экземпляра он принимает класс.Часто они используются в качестве альтернативных конструкторов для лучшего семантического использования и поддерживают наследование.
Наиболее каноническим примером встроенного метода класса является dict.fromkeys
.Он используется в качестве альтернативного конструктора dict (хорошо подходит, если вы знаете, какие у вас ключи, и хотите, чтобы для них было значение по умолчанию).
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
Когда мы создаем подкласс dict, мы можем использовать тот же конструктор, который создает экземпляр подкласса.
>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>
См. исходный код панды другие подобные примеры альтернативных конструкторов, а также см. официальную документацию Python на classmethod
и staticmethod
.
Я начал изучать язык программирования с C++, затем с Java, а затем с Python, и этот вопрос меня тоже очень беспокоил, пока я не понял простоту использования каждого из них.
Метод класса: Python, в отличие от Java и C++, не имеет перегрузки конструктора.И поэтому для достижения этого вы можете использовать classmethod
.Следующий пример объяснит это
Давайте представим, что у нас есть Person
класс, который принимает два аргумента first_name
и last_name
и создает экземпляр Person
.
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
Теперь, если возникнет необходимость создать класс, используя только одно имя, просто first_name
, ты не мочь сделайте что-то подобное в Python.
Это выдаст вам ошибку, когда вы попытаетесь создать объект (экземпляр).
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __init__(self, first_name):
self.first_name = first_name
Однако вы можете добиться того же, используя @classmethod
как указано ниже
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@classmethod
def get_person(cls, first_name):
return cls(first_name, "")
Статический метод: Это довольно просто, оно не привязано к экземпляру или классу, и вы можете просто вызвать его, используя имя класса.
Допустим, в приведенном выше примере вам нужна проверка, которая first_name
не должно превышать 20 символов, вы можете просто сделать это.
@staticmethod
def validate_name(name):
return len(name) <= 20
и вы можете просто позвонить, используя class name
Person.validate_name("Gaurang Shah")
@decorators были добавлены в Python 2.4. Если вы используете Python < 2.4, вы можете использовать функции classmethod() и staticmethod().
Например, если вы хотите создать фабричный метод (функция, возвращающая экземпляр другой реализации класса в зависимости от того, какой аргумент она получает), вы можете сделать что-то вроде:
class Cluster(object):
def _is_cluster_for(cls, name):
"""
see if this class is the cluster with this name
this is a classmethod
"""
return cls.__name__ == name
_is_cluster_for = classmethod(_is_cluster_for)
#static method
def getCluster(name):
"""
static factory method, should be in Cluster class
returns a cluster object for the given name
"""
for cls in Cluster.__subclasses__():
if cls._is_cluster_for(name):
return cls()
getCluster = staticmethod(getCluster)
Также отмечайте, что это хороший пример для использования класса -матода и статического метода, статический метод явно принадлежит классу, поскольку он использует кластер класса внутри.Методу класса нужна только информация о классе, а не экземпляр объекта.
Еще одно преимущество создания _is_cluster_for
Метод метода класса предназначен для того, чтобы подкласс мог решить изменить свою реализацию, возможно, потому, что он довольно общий и может обрабатывать более одного типа кластера, поэтому простой проверки имени класса будет недостаточно.
Я думаю, что лучший вопрос: «Когда бы вы использовали @classmethod или @staticmethod?»
@classmethod позволяет легко получить доступ к закрытым членам, связанным с определением класса.это отличный способ создавать синглтоны или фабричные классы, которые контролируют количество существующих экземпляров созданных объектов.
@staticmethod обеспечивает незначительный прирост производительности, но я еще не видел продуктивного использования статического метода внутри класса, которого нельзя было бы достичь как отдельную функцию вне класса.
Статические методы:
- Простые функции без аргументов self.
- Работа над атрибутами класса;не в атрибутах экземпляра.
- Может быть вызван как через класс, так и через экземпляр.
- Для их создания используется встроенная функция staticmethod().
Преимущества статических методов:
- Он локализует имя функции в области классов.
- Он перемещает код функции ближе к тому месту, где он используется.
Импортировать удобнее по сравнению с функциями уровня модуля, поскольку не нужно специально импортировать каждый метод.
@staticmethod def some_static_method(*args, **kwds): pass
Методы класса:
- Функции, у которых первым аргументом является имя класса.
- Может быть вызван как через класс, так и через экземпляр.
Они создаются с помощью встроенной функции classmethod.
@classmethod def some_class_method(cls, *args, **kwds): pass
@staticmethod
просто отключает функцию по умолчанию в качестве дескриптора метода.classmethod оборачивает вашу функцию в вызываемый контейнер, который передает ссылку на класс-владелец в качестве первого аргумента:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>
Собственно говоря, classmethod
имеет накладные расходы во время выполнения, но позволяет получить доступ к классу-владельцу.В качестве альтернативы я рекомендую использовать метакласс и поместить методы класса в этот метакласс:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
<class '__main__.C'>
Полное руководство о том, как использовать статические, классовые или абстрактные методы в Python. это хорошая ссылка на эту тему, и резюмируйте ее следующим образом.
@staticmethod
function — это не что иное, как функция, определенная внутри класса.Его можно вызвать без предварительного создания экземпляра класса.Его определение неизменно посредством наследования.
- Python не обязательно создавать экземпляр связанного метода для объекта.
- Это облегчает читаемость кода и не зависит от состояния самого объекта;
@classmethod
Функция также может быть вызвана без создания экземпляра класса, но ее определение следует за подклассом. Подкласс, а не родительский класс, через наследование может быть переопределен подклассом.Это потому, что первый аргумент в пользу @classmethod
функция всегда должна быть клс (сорт).
- Фабричные методы, которые используются для создания экземпляра класса, используя, например, некоторую предварительную обработку.
- Статические методы, вызывающие статические методы:если вы разделите статические методы на несколько статических методов, вам не следует жестко закодировать имя класса, а использовать методы класса
Позвольте мне сначала рассказать о сходстве между методом, украшенным @classmethod, и @staticmethod.
Сходство: Их обоих можно вызвать по Сорт сам по себе, а не только пример класса.Итак, они оба в каком-то смысле Методы класса.
Разница: Классовый метод получит сам класс в качестве первого аргумента, а статический — нет.
Таким образом, статический метод в некотором смысле не привязан к самому классу и просто висит там только потому, что может иметь связанную функциональность.
>>> class Klaus:
@classmethod
def classmthd(*args):
return args
@staticmethod
def staticmthd(*args):
return args
# 1. Call classmethod without any arg
>>> Klaus.classmthd()
(__main__.Klaus,) # the class gets passed as the first argument
# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')
# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()
()
# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)
Еще одно соображение, касающееся статического метода и метода класса, связано с наследованием.Предположим, у вас есть следующий класс:
class Foo(object):
@staticmethod
def bar():
return "In Foo"
И затем вы хотите переопределить bar()
в дочернем классе:
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
Это работает, но учтите, что теперь bar()
реализация в дочернем классе (Foo2
) больше не может использовать преимущества, присущие этому классу.Например, скажем Foo2
был метод под названием magic()
который вы хотите использовать в Foo2
реализация bar()
:
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
@staticmethod
def magic():
return "Something useful you'd like to use in bar, but now can't"
Обходным решением здесь было бы позвонить Foo2.magic()
в bar()
, но тогда вы повторяетесь (если имя Foo2
изменения, вам придется не забыть обновить это bar()
метод).
На мой взгляд, это небольшое нарушение принцип открытости/закрытости, поскольку решение, принятое в Foo
влияет на вашу способность реорганизовать общий код в производном классе (т. е. он менее открыт для расширения).Если bar()
были classmethod
с нами всё будет в порядке:
class Foo(object):
@classmethod
def bar(cls):
return "In Foo"
class Foo2(Foo):
@classmethod
def bar(cls):
return "In Foo2 " + cls.magic()
@classmethod
def magic(cls):
return "MAGIC"
print Foo2().bar()
Дает: In Foo2 MAGIC
Я попытаюсь объяснить основную разницу на примере.
class A(object):
x = 0
def say_hi(self):
pass
@staticmethod
def say_hi_static():
pass
@classmethod
def say_hi_class(cls):
pass
def run_self(self):
self.x += 1
print self.x # outputs 1
self.say_hi()
self.say_hi_static()
self.say_hi_class()
@staticmethod
def run_static():
print A.x # outputs 0
# A.say_hi() # wrong
A.say_hi_static()
A.say_hi_class()
@classmethod
def run_class(cls):
print cls.x # outputs 0
# cls.say_hi() # wrong
cls.say_hi_static()
cls.say_hi_class()
1 — мы можем напрямую вызывать статические и классовые методы без инициализации
# A.run_self() # wrong
A.run_static()
A.run_class()
2. Статический метод не может вызывать собственный метод, но может вызывать другой статический метод и метод класса.
3. Статический метод принадлежит классу и вообще не будет использовать объект.
4. Метод класса привязан не к объекту, а к классу.
@классметод:может использоваться для создания общего глобального доступа ко всем экземплярам, созданным этого класса.....например, обновление записи несколькими пользователями....Я особенно нашел это полезным при создании синглтонов. :)
@статический метод:не имеет ничего общего с классом или экземпляром, с которым он связан... но для удобства чтения можно использовать статический метод
Мой вклад демонстрирует разницу между @classmethod
, @staticmethod
, и методы экземпляра, включая то, как экземпляр может косвенно вызывать @staticmethod
.Но вместо косвенного вызова @staticmethod
Из случая, делая его частным, может быть более «питоническим». Получение чего -то из частного метода здесь не продемонстрировано, но это в основном та же концепция.
#!python3
from os import system
system('cls')
# % % % % % % % % % % % % % % % % % % % %
class DemoClass(object):
# instance methods need a class instance and
# can access the instance through 'self'
def instance_method_1(self):
return 'called from inside the instance_method_1()'
def instance_method_2(self):
# an instance outside the class indirectly calls the static_method
return self.static_method() + ' via instance_method_2()'
# class methods don't need a class instance, they can't access the
# instance (self) but they have access to the class itself via 'cls'
@classmethod
def class_method(cls):
return 'called from inside the class_method()'
# static methods don't have access to 'cls' or 'self', they work like
# regular functions but belong to the class' namespace
@staticmethod
def static_method():
return 'called from inside the static_method()'
# % % % % % % % % % % % % % % % % % % % %
# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''
# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# % % % % % % % % % % % % % % % % % % % %
# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()
# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''
# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''
# call class_method()
print(democlassObj.class_method() + '\n')
''' called from inside the class_method() '''
# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''
"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""
Методы класса, как следует из названия, используются для внесения изменений в классы, а не в объекты.Чтобы внести изменения в классы, они изменят атрибуты класса (а не атрибуты объекта), поскольку именно так вы обновляете классы.По этой причине методы класса принимают класс (обычно обозначаемый «cls») в качестве первого аргумента.
class A(object):
m=54
@classmethod
def class_method(cls):
print "m is %d" % cls.m
С другой стороны, статические методы используются для выполнения функций, которые не привязаны к классу, т.е.они не будут читать или записывать переменные класса.Следовательно, статические методы не принимают классы в качестве аргументов.Они используются для того, чтобы классы могли выполнять функции, не связанные напрямую с назначением класса.
class X(object):
m=54 #will not be referenced
@staticmethod
def static_method():
print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
Возможно, вы захотите рассмотреть разницу между:
Class A:
def foo(): # no self parameter, no decorator
pass
и
Class B:
@staticmethod
def foo(): # no self parameter
pass
Это изменилось между python2 и python3:
питон2:
>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
питон3:
>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
Итак, используя @staticmethod
для методов, вызываемых только непосредственно из класса, в Python3 стало необязательным.Если вы хотите вызывать их как из класса, так и из экземпляра, вам все равно нужно использовать метод @staticmethod
декоратор.
Остальные случаи хорошо описаны в ответе unutbus.
Анализ @staticmethod буквально предоставление различных идей.
Обычный метод класса — это неявный динамичный метод, который принимает экземпляр в качестве первого аргумента.
Напротив, статический метод не принимает экземпляр в качестве первого аргумента, поэтому называется 'статический'.
Статический метод действительно является такой же нормальной функцией, как и те, что находятся вне определения класса.
К счастью, он сгруппирован в класс только для того, чтобы быть ближе к тому месту, где он применяется, или вы можете прокрутить его, чтобы найти.
Короткий ответ.Первый аргумент:
- нормальный метод:первый аргумент — текущий объект
- метод класса:первый аргумент — класс текущего объекта
- статический метод:первый аргумент удален
Более длинный ответ:
нормальный метод
Когда вызывается метод объекта, ему автоматически присваивается дополнительный аргумент. self
в качестве первого аргумента.То есть метод
def f(self, x, y)
должен вызываться с двумя аргументами. self
передается автоматически, и это сам объект.
метод класса
Когда метод декорирован
@classmethod
def f(cls, x, y)
автоматически предоставляемый аргумент не является self
, но класс self
.
статический метод
Когда метод декорирован
@staticmethod
def f(x, y)
метод не дано любой автоматический аргумент вообще.Ему задаются только параметры, с которыми он вызывается.
обычаи
classmethod
в основном используется для альтернативных конструкторов.staticmethod
не использует состояние объекта.Это может быть внешняя по отношению к классу функция.Внутри класса он помещается только для группировки функций со схожей функциональностью (например, как в JavaMath
статические методы класса)
class Point
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def frompolar(cls, radius, angle):
"""The `cls` argument is the `Point` class itself"""
return cls(radius * cos(angle), radius * sin(angle))
@staticmethod
def angle(x, y):
return atan(y, x)
p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)
angle = Point.angle(3, 2)
Быстрый анализ идентичных в остальном методов iPython показывает, что @staticmethod
дает незначительный прирост производительности (в наносекундах), но в остальном, похоже, он не выполняет никакой функции.Кроме того, любой прирост производительности, вероятно, будет сведен на нет дополнительной работой по обработке метода через staticmethod()
во время компиляции (которая происходит перед выполнением любого кода при запуске скрипта).
Ради читаемости кода я бы избегал @staticmethod
если только ваш метод не будет использоваться для большого количества работы, где счет наносекунд.