В чем разница между функцией, украшенной @staticmethod
и одной, украшенной @classmethod
?
python
oop
methods
python-decorators
Дэрил Спитцер
источник
источник
Ответы:
Может быть, пример кода поможет: обратите внимание на разницу в сигнатурах вызовов
foo
,class_foo
иstatic_foo
:Ниже приведен обычный способ вызова экземпляра объекта методом. Экземпляр объекта,
a
неявно передается в качестве первого аргумента.При использовании методов класса класс экземпляра объекта неявно передается в качестве первого аргумента вместо
self
.Вы также можете позвонить
class_foo
с помощью класса. На самом деле, если вы определяете что-то как метод класса, это, вероятно, потому, что вы намереваетесь вызывать это из класса, а не из экземпляра класса.A.foo(1)
поднял бы TypeError, ноA.class_foo(1)
работает просто отлично:Одно из применений, которые люди нашли для методов класса, - это создание наследуемых альтернативных конструкторов .
При использовании статических методов ни
self
(экземпляр объекта), ниcls
(класс) неявно не передаются в качестве первого аргумента. Они ведут себя как простые функции, за исключением того, что вы можете вызывать их из экземпляра или класса:Статические методы используются для группировки функций, которые имеют некоторую логическую связь с классом для класса.
foo
это просто функция, но когда вы вызываете ее,a.foo
вы не просто получаете функцию, вы получаете «частично примененную» версию функции с экземпляром объекта,a
связанным в качестве первого аргумента функции.foo
ожидает 2 аргумента, в то время какa.foo
ожидает только 1 аргумент.a
связан сfoo
. Вот что подразумевается под термином «связанный» ниже:С
a.class_foo
,a
не связанclass_foo
, скорее классA
связан сclass_foo
.Здесь со статическим методом, даже если это метод,
a.static_foo
просто возвращается хорошая функция ole без привязки аргументов.static_foo
ожидает 1 аргумент иa.static_foo
1 аргумент тоже.И, конечно, то же самое происходит, когда вы звоните
static_foo
вместе с классомA
.источник
@staticmethod
может помочь организовать ваш код, переопределяясь подклассами. Без этого у вас были бы варианты функции, плавающей в пространстве имен модуля.@staticmethod
- вы можете использовать его для удаления Cruft. Я реализую язык программирования на Python - библиотечные функции используют статическийexecute
метод, где пользовательские функции требуют аргументов экземпляра (т. Е. Тела функции). Этот декоратор устраняет предупреждения «неиспользуемый параметр self» в инспекторе PyCharm.STATICMETHOD это метод , который ничего не знает о классе или экземпляре он был вызван. Он просто получает аргументы, которые были переданы, без первого неявного аргумента. Это в основном бесполезно в Python - вы можете просто использовать функцию модуля вместо статического метода.
Classmethod , с другой стороны, это метод , который получает передается класс он был вызван на или класс экземпляра он был вызван, в качестве первого аргумента. Это полезно, когда вы хотите, чтобы метод был фабрикой для класса: поскольку он получает фактический класс, для которого он был вызван, в качестве первого аргумента, вы всегда можете создать экземпляр нужного класса, даже если задействованы подклассы. Посмотрите, например, как
dict.fromkeys()
метод класса возвращает экземпляр подкласса при вызове в подклассе:источник
По сути,
@classmethod
метод, первым аргументом которого является класс, из которого он вызывается (а не экземпляр класса),@staticmethod
не имеет никаких неявных аргументов.источник
Официальные документы по питону:
@classmethod
@staticmethod
источник
Вот небольшая статья по этому вопросу
источник
Чтобы решить, использовать ли @staticmethod или @classmethod, вы должны заглянуть внутрь своего метода. Если ваш метод обращается к другим переменным / методам в вашем классе, тогда используйте @classmethod . С другой стороны, если ваш метод не касается других частей класса, используйте @staticmethod.
источник
cls._counter
все равно будет,cls._counter
даже если код помещен в другой класс или имя класса изменено.Apple._counter
специфичен дляApple
класса; для другого класса или при изменении имени класса вам нужно будет изменить ссылочный класс.Возможно, вы видели код Python, подобный этому псевдокоду, который демонстрирует сигнатуры различных типов методов и предоставляет строку документации для объяснения каждого из них:
Нормальный метод экземпляра
Сначала я объясню
a_normal_instance_method
. Это точно называется « метод экземпляра ». Когда используется метод экземпляра, он используется как частичная функция (в отличие от функции total, определенной для всех значений при просмотре в исходном коде), то есть при использовании первый из аргументов предопределен как экземпляр объект со всеми заданными атрибутами. Он имеет экземпляр объекта, связанный с ним, и он должен быть вызван из экземпляра объекта. Как правило, он будет обращаться к различным атрибутам экземпляра.Например, это экземпляр строки:
если мы используем метод экземпляра,
join
в этой строке, чтобы присоединиться к другой итерируемой, это, очевидно, является функцией экземпляра, в дополнение к функции итеративного списка['a', 'b', 'c']
:Связанные методы
Методы экземпляра могут быть связаны через точечный поиск для последующего использования.
Например, это связывает
str.join
метод с':'
экземпляром:И позже мы можем использовать это как функцию, с которой уже связан первый аргумент. Таким образом, он работает как частичная функция в экземпляре:
Статический метод
Статический метод не принимает экземпляр в качестве аргумента.
Это очень похоже на функцию уровня модуля.
Однако функция уровня модуля должна находиться в модуле и специально импортироваться в другие места, где она используется.
Однако, если он присоединен к объекту, он будет удобно следовать за объектом через импорт и наследование.
Пример статического метода
str.maketrans
, перенесенный изstring
модуля в Python 3. Он делает таблицу перевода пригодной для использованияstr.translate
. Это выглядит довольно глупо при использовании из экземпляра строки, как показано ниже, но импорт функции изstring
модуля довольно неуклюжий, и приятно иметь возможность вызывать его из класса, как вstr.maketrans
В Python 2 вы должны импортировать эту функцию из все менее полезного строкового модуля:
Метод класса
Метод класса похож на метод экземпляра в том, что он принимает неявный первый аргумент, но вместо того, чтобы брать экземпляр, он принимает класс. Часто они используются в качестве альтернативных конструкторов для лучшего семантического использования, и это будет поддерживать наследование.
Наиболее каноническим примером встроенного метода класса является
dict.fromkeys
. Он используется в качестве альтернативного конструктора dict (хорошо подходит для случаев, когда вы знаете, какие у вас ключи, и хотите для них значение по умолчанию.)Когда мы создаем подкласс dict, мы можем использовать тот же конструктор, который создает экземпляр подкласса.
Посмотрите исходный код Pandas для других подобных примеров альтернативных конструкторов, а также посмотрите официальную документацию Python по
classmethod
иstaticmethod
.источник
Я начал изучать язык программирования на C ++, а затем на Java, а затем на Python, и поэтому этот вопрос меня тоже беспокоил, пока я не понял простое использование каждого из них.
Метод класса: Python в отличие от Java и C ++ не имеет перегрузки конструктора. И поэтому для достижения этого вы могли бы использовать
classmethod
. Следующий пример объяснит этоДавайте рассмотрим у нас есть
Person
класс , который принимает два аргументаfirst_name
иlast_name
и создает экземплярPerson
.Теперь, если требование возникает там, где вам нужно создать класс, используя только одно имя, просто a
first_name
, вы не можете сделать что-то подобное в Python.Это даст вам ошибку, когда вы попытаетесь создать объект (экземпляр).
Тем не менее, вы можете достичь того же, используя
@classmethod
как указано нижеСтатический метод: это довольно просто, он не привязан к экземпляру или классу, и вы можете просто вызвать его, используя имя класса.
Итак, скажем, в приведенном выше примере вам нужна проверка, которая
first_name
не должна превышать 20 символов, вы можете просто сделать это.и вы могли бы просто позвонить с помощью
class name
источник
def __init__(self, first_name, last_name="")
вместо метода классаget_person
. Также результат будет точно таким же в этом случае.Я думаю, что лучший вопрос: "Когда бы вы использовали @classmethod против @staticmethod?"
@classmethod позволяет вам легко получить доступ к закрытым членам, связанным с определением класса. это отличный способ создавать синглтоны или фабричные классы, которые контролируют количество экземпляров созданных объектов.
@staticmethod обеспечивает предельный прирост производительности, но мне еще предстоит увидеть продуктивное использование статического метода в классе, который не может быть реализован как отдельная функция вне класса.
источник
@decorators были добавлены в python 2.4. Если вы используете python <2.4, вы можете использовать функции classmethod () и staticmethod ().
Например, если вы хотите создать фабричный метод (функция, возвращающая экземпляр другой реализации класса в зависимости от того, какой аргумент он получает), вы можете сделать что-то вроде:
Также обратите внимание, что это хороший пример использования метода класса и статического метода. Статический метод явно принадлежит классу, поскольку он использует класс Cluster для внутреннего использования. Метод класса нуждается только в информации о классе, а не в экземпляре объекта.
Еще одно преимущество превращения
_is_cluster_for
метода в метод класса - это то, что подкласс может решить изменить свою реализацию, возможно, потому, что он довольно универсален и может обрабатывать более одного типа кластера, поэтому простой проверки имени класса будет недостаточно.источник
Статические методы:
Преимущества статических методов:
Удобнее импортировать функции по сравнению с функциями уровня модуля, поскольку каждый метод не нужно специально импортировать
Методы класса:
Они создаются с помощью встроенной функции classmethod.
источник
@staticmethod
просто отключает функцию по умолчанию как дескриптор метода. classmethod оборачивает вашу функцию в вызываемый контейнер, который передает ссылку на собственный класс в качестве первого аргумента:На самом деле,
classmethod
имеет накладные расходы времени выполнения, но позволяет получить доступ к классу-владельцу. В качестве альтернативы я рекомендую использовать метакласс и поместить методы класса в этот метакласс:источник
c = C(); c.foo()
поднимает AttributeError, вам придется сделатьtype(c).foo()
. Это также может считаться особенностью - хотя я не могу понять, почему вы захотите.Полное руководство по использованию статических, классовых или абстрактных методов в Python - одна из хороших ссылок на эту тему, и подытожьте ее следующим образом.
@staticmethod
Функция - это не что иное, как функция, определенная внутри класса. Он вызывается без создания экземпляра класса первым. Это определение является неизменным через наследование.@classmethod
Функция также может вызываться без создания экземпляра класса, но ее определение следует за Подклассом, а не Родительский класс посредством наследования может быть переопределен подклассом. Это потому, что первый аргумент для@classmethod
функции всегда должен быть cls (class).источник
Отличается только первый аргумент :
Более детально...
нормальный метод
Когда вызывается метод объекта, ему автоматически присваивается дополнительный аргумент в
self
качестве первого аргумента. То есть методдолжен быть вызван с 2 аргументами.
self
автоматически передается, и это сам объект .метод класса
Когда метод оформлен
автоматически предоставленный аргумент не
self
, но классself
.статический метод
Когда метод оформлен
метод не имеет никакого автоматического аргумента вообще. Дается только параметры, с которыми он вызывается.
обыкновений
classmethod
в основном используется для альтернативных конструкторов.staticmethod
не использует состояние объекта. Это может быть функция, внешняя по отношению к классу. Он помещается только внутри класса для группировки функций с похожей функциональностью (например, какMath
статические методы класса Java )источник
Позвольте мне сначала рассказать о сходстве метода, украшенного @classmethod vs @staticmethod.
Сходство: оба они могут быть вызваны для самого класса , а не только для экземпляра класса. Итак, оба они в некотором смысле являются методами класса .
Разница: метод класса получит сам класс в качестве первого аргумента, а метод статики - нет.
Таким образом, статический метод, в некотором смысле, не связан с самим классом и просто висит там только потому, что он может иметь связанную функциональность.
источник
Еще одно соображение относительно статического метода по сравнению с классическим методом связано с наследованием. Скажем, у вас есть следующий класс:
И затем вы хотите переопределить
bar()
в дочернем классе:Это работает, но обратите внимание, что теперь
bar()
реализация в дочернем классе (Foo2
) больше не может использовать в своих интересах что-то определенное для этого класса. Например, у sayFoo2
был вызван метод,magic()
который вы хотите использовать приFoo2
реализацииbar()
:Обходной путь здесь будет звонить
Foo2.magic()
вbar()
, но тогда вы повторив себя (если имяFoo2
изменения, вы должны помнить , чтобы обновить этотbar()
метод).Для меня это незначительное нарушение принципа открытого / закрытого , поскольку принятое решение
Foo
влияет на вашу способность реорганизовывать общий код в производном классе (то есть он менее открыт для расширения). Еслиbar()
быclassmethod
мы были в порядке:дает:
In Foo2 MAGIC
источник
Я попытаюсь объяснить основную разницу на примере.
1 - мы можем напрямую вызывать методы static и classmethods без инициализации
2- Статический метод не может вызвать метод self, но может вызвать другой статический метод и метод класса
3- Статический метод принадлежит классу и не будет использовать объект вообще.
4- Метод класса связан не с объектом, а с классом.
источник
@classmethod: может использоваться для создания общего глобального доступа ко всем экземплярам, созданным в этом классе ..... например, при обновлении записи несколькими пользователями .... В частности, я обнаружил, что это полезно при создании синглетонов ...: )
Метод @static: не имеет ничего общего с классом или экземпляром, связанным с ... но для удобства чтения можно использовать статический метод
источник
Вы можете рассмотреть разницу между:
а также
Это изменилось между python2 и python3:
python2:
python3:
Поэтому использование
@staticmethod
для методов, вызываемых только из класса, стало необязательным в python3. Если вы хотите вызывать их как из класса, так и из экземпляра, вам все равно нужно использовать@staticmethod
декоратор.Другие случаи были хорошо охвачены ответом unutbus.
источник
Метод класса получает класс как неявный первый аргумент, так же, как метод экземпляра получает экземпляр. Это метод, который привязан к классу, а не к объекту класса. Он имеет доступ к состоянию класса, так как принимает параметр класса, который указывает на класс, а не на экземпляр объекта. Он может изменять состояние класса, которое будет применяться ко всем экземплярам класса. Например, он может изменить переменную класса, которая будет применима ко всем экземплярам.
С другой стороны, статический метод не получает неявный первый аргумент по сравнению с методами класса или методами экземпляра. И не может получить доступ или изменить состояние класса. Он принадлежит только классу, потому что с точки зрения дизайна это правильный путь. Но с точки зрения функциональности не связан, во время выполнения, с классом.
в качестве руководства используйте статические методы в качестве утилит, используйте методы класса, например, как фабрику. Или, может быть, определить синглтон. И используйте методы экземпляров для моделирования состояния и поведения экземпляров.
Надеюсь, мне было ясно!
источник
Мой вклад демонстрирует разницу среди
@classmethod
,@staticmethod
и методов экземпляра, в том числе , как экземпляр может косвенно называть@staticmethod
. Но вместо того, чтобы косвенно вызывать a@staticmethod
из экземпляра, сделать его частным может быть более «питонным». Получение чего-то из закрытого метода здесь не продемонстрировано, но это в основном та же концепция.источник
Методы класса, как следует из названия, используются для внесения изменений в классы, а не в объекты. Чтобы внести изменения в классы, они изменят атрибуты класса (не атрибуты объекта), поскольку именно так вы обновляете классы. По этой причине методы класса принимают класс (условно обозначаемый как «cls») в качестве первого аргумента.
Статические методы, с другой стороны, используются для выполнения функций, которые не связаны с классом, т.е. они не будут читать или записывать переменные класса. Следовательно, статические методы не принимают классы в качестве аргументов. Они используются для того, чтобы классы могли выполнять функции, которые не имеют прямого отношения к назначению класса.
источник
Анализируйте @staticmethod буквально предоставляя различные идеи.
Обычный метод класса - это неявный динамический метод, который принимает экземпляр в качестве первого аргумента.
Напротив, метод static не принимает экземпляр в качестве первого аргумента, поэтому он называется «статическим» .
Статический метод действительно является такой же нормальной функцией, как и те, которые находятся вне определения класса.
Он, к счастью, сгруппирован в класс только для того, чтобы стоять ближе там, где он применяется, или вы можете прокрутить круг, чтобы найти его.
источник
Я думаю, что дать чисто Python-версию
staticmethod
иclassmethod
поможет понять разницу между ними на уровне языка.Оба они являются дескрипторами, не относящимися к данным (было бы легче понять их, если вы сначала знакомы с дескрипторами ).
источник
staticmethod не имеет доступа к объектам объекта, класса или родительских классов в иерархии наследования. Он может быть вызван непосредственно в классе (без создания объекта).
classmethod не имеет доступа к атрибутам объекта. Однако он может обращаться к атрибутам класса и родительских классов в иерархии наследования. Он может быть вызван непосредственно в классе (без создания объекта). Если вызывается в объекте, то это то же самое, что и обычный метод, который не
self.<attribute(s)>
обращается и не обращается кself.__class__.<attribute(s)>
только .Думаю, у нас есть класс
b=2
, мы создадим объект и заново установим егоb=4
в нем. Статический метод не может получить доступ ни к чему из предыдущего. Classmethod может получить доступ.b==2
только черезcls.b
. Нормальный метод может получить доступ как:.b==4
через, такself.b
и.b==2
черезself.__class__.b
.Мы могли бы следовать стилю KISS (пусть он будет простым, глупым): не используйте статические методы и методы классов, не используйте классы без их создания, обращайтесь только к атрибутам объекта
self.attribute(s)
. Есть языки, где ООП реализован таким образом, и я думаю, что это неплохая идея. :)источник
Быстрый взлом других идентичных методов в iPython показывает, что
@staticmethod
дает незначительный прирост производительности (в наносекундах), но в остальном он, похоже, не работает. Кроме того, любое повышение производительности, вероятно, будет устранено дополнительной работой по обработке методаstaticmethod()
во время компиляции (что происходит до выполнения любого кода при запуске сценария).Ради читабельности кода я бы избегал,
@staticmethod
если ваш метод не будет использоваться для нагрузок, где подсчитываются наносекунды.источник