В чем разница между @staticmethod и @classmethod в Python?

В чем разница между функцией, украшенной с помощью @staticmethod и одной, украшенной @classmethod ?

19 Solutions collect form web for “В чем разница между @staticmethod и @classmethod в Python?”

Может быть, немного пример кода поможет: Обратите внимание на разницу в сигнатурах вызовов 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)"%xa=A() 

Ниже приведен обычный способ, которым экземпляр объекта вызывает метод. Экземпляр объекта a неявно передается в качестве первого аргумента.

 a.foo(1) # executing foo(<__main__.A object at 0xb7dbef0c>,1) 

С помощью classmethod класс экземпляра объекта неявно передается как первый аргумент вместо 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) 

Одним из методов, которые люди использовали для методов класса, является создание наследуемых альтернативных конструкторов .


С помощью staticmethods ни self (экземпляр объекта), ни cls (класс) неявно передаются в качестве первого аргумента. Они ведут себя как простые функции, за исключением того, что вы можете вызывать их из экземпляра или класса:

 a.static_foo(1) # executing static_foo(1) A.static_foo('hi') # executing static_foo(hi) 

Staticmethods используются для группировки функций, которые имеют некоторую логическую связь с классом класса.


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'>> 

Здесь, с помощью staticmethod, хотя это метод, a.static_foo просто возвращает хорошую функцию ole без привязки аргументов. 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 это бесполезно – вы можете просто использовать функцию модуля вместо staticmethod.

С другой стороны, classmethod – это метод, который получает переданный класс, на который он был вызван, или класс экземпляра, на который он был вызван, в качестве первого аргумента. Это полезно, если вы хотите, чтобы этот метод был фабрикой для класса: поскольку он получает фактический класс, который он вызывал в качестве первого аргумента, вы всегда можете создать экземпляр правильного класса, даже если задействованы подклассы. Обратите внимание, например, как dict.fromkeys() , classmethod, возвращает экземпляр подкласса при вызове в подклассе:

 >>> class DictSubclass(dict): ... def __repr__(self): ... return "DictSubclass" ... >>> dict.fromkeys("abc") {'a': None, 'c': None, 'b': None} >>> DictSubclass.fromkeys("abc") DictSubclass >>> 

В основном @classmethod делает метод, первым аргументом которого является класс, из которого он вызван (а не экземпляр класса), @staticmethod не имеет никаких неявных аргументов.

Официальные документы python:

@classmethod

Метод класса получает класс как неявный первый аргумент, как метод экземпляра получает экземпляр. Чтобы объявить метод класса, используйте эту идиому:

 class C: @classmethod def f(cls, arg1, arg2, ...): ... 

Форма @classmethod является декоратором функций – подробности см. В описании определений функций в определениях функций .

Его можно вызвать либо в классе (например, Cf() ), либо в экземпляре (например, C().f() ). Экземпляр игнорируется, за исключением его класса. Если метод класса вызывается для производного класса, объект производного класса передается как подразумеваемый первый аргумент.

Методы класса отличаются от статических методов C ++ или Java. Если вы хотите этого, см. staticmethod() в этом разделе.

@staticmethod

Статический метод не получает неявный первый аргумент. Чтобы объявить статический метод, используйте эту идиому:

 class C: @staticmethod def f(arg1, arg2, ...): ... 

Форма @staticmethod – это декоратор функций – подробнее см. Описание определений функций в определениях функций .

Его можно вызвать либо в классе (например, Cf() ), либо в экземпляре (например, C().f() ). Экземпляр игнорируется, за исключением его класса.

Статические методы в Python аналогичны тем, которые были найдены в Java или C ++. Для более продвинутой концепции см. classmethod() в этом разделе.

Вот короткая статья по этому вопросу

Функция @staticmethod – это не что иное, как функция, определенная внутри класса. Он может быть вызван без создания экземпляра класса. Это определение неизменно через наследование.

Функция @classmethod также может быть вызвана без создания экземпляра класса, но ее определение следует через класс Sub, а не родительский класс, через наследование. Это потому, что первым аргументом для функции @classmethod всегда должен быть cls (класс).

В чем разница между @staticmethod и @classmethod в Python?

Возможно, вы видели код Python, подобный этому псевдокоду, который демонстрирует подписи различных типов методов и предоставляет docstring для объяснения каждого из них:

 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'> 

См. Исходный код pandas для других аналогичных примеров альтернативных конструкторов и см. Также официальную документацию Python по classmethod и staticmethod .

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

Я думаю, что лучший вопрос: «Когда вы будете использовать @classmethod vs @staticmethod?»

@classmethod позволяет вам легко получить доступ к закрытым членам, которые связаны с определением класса. это отличный способ сделать одиночные игры или фабричные классы, которые контролируют количество экземпляров созданных объектов.

@staticmethod обеспечивает предельную прибыль от производительности, но мне еще предстоит увидеть продуктивное использование статического метода в классе, который не может быть реализован как отдельная функция вне класса.

@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 имеет служебные classmethod во время выполнения, но позволяет получить доступ к классу владельца. В качестве альтернативы я рекомендую использовать метакласс и помещать методы класса в этот метакласс:

 >>> class CMeta(type): ... def foo(cls): ... print cls ... >>> class C(object): ... __metaclass__ = CMeta ... >>> C.foo() <class '__main__.C'> 

Статические методы:

  • Простые функции без аргументов.
  • Работа над атрибутами класса; а не атрибуты экземпляра.
  • Может быть вызван как через класс, так и экземпляр.
  • Для их создания используется встроенная функция staticmethod ().

Преимущества статических методов:

  • Он локализует имя функции в классе
  • Он перемещает код функции ближе к тому, где он используется
  • Более удобно импортировать по сравнению с функциями уровня модуля, поскольку каждый метод не нужно специально импортировать

     @staticmethod def some_static_method(*args, **kwds): pass 

Методы класса:

  • Функции, которые имеют первый аргумент как имя класса.
  • Может быть вызван как через класс, так и экземпляр.
  • Они создаются с помощью встроенной функции classmethod.

      @classmethod def some_class_method(cls, *args, **kwds): pass 

@classmethod означает : когда этот метод вызывается, мы передаем класс в качестве первого аргумента вместо экземпляра этого класса (как обычно мы делаем с методами). Это означает, что вы можете использовать класс и его свойства внутри этого метода, а не конкретный экземпляр.

@staticmethod означает: когда вызывается этот метод, мы не передаем ему экземпляр класса (как это обычно бывает с методами). Это означает, что вы можете поместить функцию внутри класса, но вы не можете получить доступ к экземпляру этого класса (это полезно, когда ваш метод не использует экземпляр).

Окончательное руководство по использованию статических, классных или абстрактных методов в Python является одной из хороших ссылок для этой темы и сводит их к следующему.

Функция @staticmethod – это не что иное, как функция, определенная внутри класса. Он может быть вызван без создания экземпляра класса. Это определение неизменно через наследование.

  • Python не должен создавать экземпляр связанного метода для объекта.
  • Это облегчает читаемость кода и не зависит от состояния самого объекта;

Функция @classmethod также может быть @classmethod без создания экземпляра класса, но ее определение следует подкласс Sub, а не родительский класс, через наследование, может быть переопределено подклассом. Это потому, что первым аргументом для функции @classmethod всегда должен быть cls (класс).

  • Фабричные методы , которые используются для создания экземпляра для класса, использующего, например, некоторую предварительную обработку.
  • Статические методы, вызывающие статические методы : если вы разбиваете статические методы несколькими статическими методами, вам не следует жестко кодировать имя класса, но использовать методы класса

Еще одно соображение относительно метода staticmethod vs classmethod связано с наследованием. Скажем, у вас есть следующий класс:

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

Для меня это небольшое нарушение принципа open / closed , так как решение, принятое в 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

В Python classmethod получает класс как неявный первый аргумент. Класс экземпляра объекта неявно передается как первый аргумент. Это может быть полезно, когда вы хотите, чтобы этот метод был фабрикой класса, поскольку он получает фактический класс (который называется методом) в качестве первого аргумента, можно создать экземпляр правильного класса, даже если это касается и подклассов.

Статический метод – это просто функция, определенная внутри класса. Он ничего не знает о классе или экземпляре, на который он был вызван, и получает только аргументы, которые были переданы без какого-либо неявного первого аргумента. Пример:

 class Test(object): def foo(self, a): print "testing (%s,%s)"%(self,a) @classmethod def foo_classmethod(cls, a): print "testing foo_classmethod(%s,%s)"%(cls,a) @staticmethod def foo_staticmethod(a): print "testing foo_staticmethod(%s)"%a test = Test() 

staticmethods используются для группировки функций, которые имеют некоторое логическое соединение с классом класса.

Я попытаюсь объяснить основную разницу, используя пример.

 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 Ax # 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 – мы можем напрямую вызвать статические и classmethods без инициализации

 # A.run_self() # wrong A.run_static() A.run_class() 

2- Статический метод не может вызвать метод self, но может вызывать другие статические и classmethod

3- Статический метод принадлежит классу и вообще не будет использовать объект.

Метод класса не связан с объектом, а с классом.

@classmethod: можно использовать для создания общего глобального доступа ко всем экземплярам, ​​созданным из этого класса ….. например, обновлять запись несколькими пользователями … Я особенно нашел, что это полезно при создании синглов. )

@static метод: не имеет никакого отношения к классу или экземпляру, связанному с … но для удобства чтения можно использовать статический метод

 #!/usr/bin/python #coding:utf-8 class Demo(object): def __init__(self,x): self.x = x @classmethod def addone(self, x): return x+1 @staticmethod def addtwo(x): return x+2 def addthree(self, x): return x+3 def main(): print Demo.addone(2) print Demo.addtwo(2) #print Demo.addthree(2) #Error demo = Demo(2) print demo.addthree(2) if __name__ == '__main__': main() 

Быстрое взлома одних и тех же методов в iPython показывает, что @staticmethod дает предельный прирост производительности (в наносекундах), но в остальном он, похоже, не функционирует. Кроме того, любые staticmethod() производительности, вероятно, будут уничтожены дополнительной работой по обработке метода с помощью staticmethod() во время компиляции (что происходит до выполнения любого кода при запуске скрипта).

Для удобства чтения кода я бы избегал @staticmethod если ваш метод не будет использоваться для нагрузок работы, где подсчитываются наносекунды.

Interesting Posts

Python: функция, которая возвращает dict, чьими ключами являются имена входных аргументов

Интерполяция ConfigParser и String с переменной env

Объединение документации Sphinx из нескольких подпроектов: обработка индексов, настройка синхронизации и т. Д.

Отложить код для последующего выполнения в python (например, setTimeout в javascript)

назначить вывод печати переменной в python

Django эквивалент массива значений форм / ассоциативного массива PHP

Безопасная система аутентификации в python?

Импорт Python между модулями и глобальными переменными

Как создать объект кода в python?

Не удалось выполнить запрос objects.all ()

Как испустить событие SocketIO на сервере

Как проверить, содержит ли строка какие-либо буквы из алфавита?

Django, как использовать декоратор “ receiver“ для класса вместо функции

Как реализовать сервер Comet с Python?

Преобразование Pandas DataFrame в оранжевую таблицу

Python - лучший язык программирования в мире.