В чем разница между @staticmethod и @classmethod? - программирование

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

В чем разница между функцией, украшенной @staticmethod, а другая - @classmethod?

4b9b3361

Ответ 1

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

Ответ 2

Статический метод - это метод, который ничего не знает о классе или экземпляре, на который он был вызван. Он просто получает аргументы, которые были переданы, не подразумевается первый аргумент. В 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
>>> 

Ответ 3

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

Ответ 4

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

@classmethod

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

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

Форма @classmethod является функцией decorator - см. описание определения функций в Функция определения.

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

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

@staticmethod

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

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

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

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

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

Ответ 5

Здесь - короткая статья по этому вопросу

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

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

Ответ 6

Чтобы решить, использовать ли @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

Ответ 7

В чем разница между @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'>

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

Ответ 8

Я начал изучать язык программирования с 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")

Ответ 9

@decorators были добавлены в python 2.4 Если вы используете python < 2.4 вы можете использовать функцию classmethod() и staticmethod().

Например, если вы хотите создать метод factory (функция, возвращающая экземпляр другой реализации класса в зависимости от того, какой аргумент он получает), вы можете сделать что-то вроде:

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

Ответ 10

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

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

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

Ответ 11

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

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

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

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

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

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

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

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

Ответ 12

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

Ответ 13

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

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

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

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

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

Ответ 14

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

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

Ответ 15

Позвольте мне сначала рассказать о сходстве метода, украшенного @classmethod vs @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',)

Ответ 16

Другое соображение относительно метода 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, влияет на вашу способность refactor common code в производном классе (т.е. он менее открыт для расширения). Если 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

Ответ 17

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

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

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

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

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

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

Ответ 18

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

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

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

Ответ 19

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

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

Ответ 20

Первый аргумент отличается:

  • обычный метод: первый аргумент (автоматически) текущий объект
  • classmethod: первый аргумент (автоматически) класс текущего объекта
  • staticmethod: первый аргумент не передается автоматически

Более подробно...

нормальный метод

Когда вызывается метод объекта, ему автоматически присваивается дополнительный аргумент self в качестве первого аргумента. То есть метод

def f(self, x, y)

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

метод класса

Когда метод оформлен

@classmethod
def f(cls, x, y)

автоматически предоставленный аргумент - не self, а класс self.

статический метод

Когда метод оформлен

@staticmethod
def f(x, y)

метод вообще не имеет автоматического аргумента. Он задается только параметрами, с которыми он вызывается.

обыкновений

  • classmethod в основном используется для альтернативных конструкторов.
  • staticmethod не использует состояние объекта. Это может быть функция, внешняя по отношению к классу. Он помещается только внутри класса для группировки функций со схожей функциональностью (например, как статические методы класса Java Math)
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):
        """this could be outside the class, but we put it here 
just because we think it is logically related to the class."""
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

Ответ 21

Вы можете рассмотреть разницу между:

Class A:
    def foo():  # no self parameter, no decorator
        pass

а также

Class B:
    @staticmethod
    def foo():  # no self parameter
        pass

Это изменилось между python2 и python3:

python2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

Поэтому использование @staticmethod для методов, вызываемых только непосредственно из класса, стало необязательным в python3. Если вы хотите вызывать их как из класса, так и из экземпляра, вам все равно нужно использовать декоратор @staticmethod.

Остальные случаи были хорошо охвачены ответом unutbus.

Ответ 22

метод класса vs статический метод в Python

Метод класса

Декоратор @classmethod - встроенный декоратор функций, который является выражением, которое оценивается после определения вашей функции. Результат этой оценки затеняет ваше определение функции.

Метод класса получает класс как неявный первый аргумент, так же как метод экземпляра получает экземпляр

Синтаксис:

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

fun: function that needs to be converted into a class method
returns: a class method for function.
  • Метод класса - это метод, связанный с классом, а не с объектом класса.
  • Они имеют доступ к состоянию класса, поскольку он принимает параметр класса, который указывает на класс, а не на экземпляр объекта.
  • Он может изменять состояние класса, которое будет применяться во всех экземплярах класса. Например, он может модифицировать переменную класса, которая будет применима ко всем экземплярам.

Статический метод

Статический метод не получает неявный первый аргумент.

Синтаксис:

class C(object):
    @staticmethod
    def fun(arg1, arg2, ...):
        ...
returns: a static method for function fun.
  • Статический метод также является методом, который связан с классом, а не с объектом класса.
  • Статический метод не может получить доступ или изменить состояние класса.
  • Он присутствует в классе, потому что имеет смысл, чтобы метод присутствовал в классе.

Метод класса против статического метода

  • Метод класса принимает cls как первый параметр, тогда как статический метод не нуждается в конкретных параметрах.
  • Метод класса может получить доступ или изменить состояние класса, когда статический метод не может получить доступ или изменить его.
  • Мы используем @classmethod decorator в python для создания метода класса, и мы используем @staticmethod decorator для создания статического метода в python.

Когда использовать что?

  • Обычно мы используем метод класса для создания заводских методов. Фабричные методы возвращают объект класса (похожий на конструктор) для разных вариантов использования.
  • Обычно мы используем статические методы для создания служебных функций.

Как определить метод класса и статический метод?

Чтобы определить метод класса в python, мы используем декоратор @classmethod и определяем статический метод, которым мы используем декоратор @staticmethod.

Давайте посмотрим на пример, чтобы понять разницу между ними. Скажем, мы хотим создать класс Person. Теперь python не поддерживает перегрузку метода, например C++ или Java, поэтому мы используем методы класса для создания заводских методов. В приведенном ниже примере мы используем метод класса для создания объекта person из года рождения.

Как объяснялось выше, мы используем статические методы для создания служебных функций. В приведенном ниже примере мы используем статический метод для проверки того, является ли человек взрослым или нет.

Реализация

# Python program to demonstrate 
# use of class method and static method.
from datetime import date

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # a class method to create a Person object by birth year.
    @classmethod
    def fromBirthYear(cls, name, year):
        return cls(name, date.today().year - year)

    # a static method to check if a Person is adult or not.
    @staticmethod
    def isAdult(age):
        return age > 18

person1 = Person('mayank', 21)
person2 = Person.fromBirthYear('mayank', 1996)

print person1.age
print person2.age

# print the result
print Person.isAdult(22)

Вывод

21
21
True

Справка

Ответ 23

Мой вклад демонстрирует разницу между @classmethod, @staticmethod и экземплярами, включая то, как экземпляр может косвенно вызвать @staticmethod. Но вместо косвенного вызова @staticmethod из экземпляра, делая его частным, может быть более "pythonic". Получение чего-то из частного метода здесь не показано, но в принципе это одна и та же концепция.

#!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 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)
'''
"""

Ответ 24

Методы класса, как следует из названия, используются для внесения изменений в классы, а не в объекты. Чтобы внести изменения в классы, они будут изменять атрибуты класса (а не атрибуты объекта), поскольку именно так вы обновляете классы. Именно по этой причине методы класса берут класс (условно обозначаемый "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."

Ответ 25

Анализ @staticmethod буквально предоставляет разные идеи.

Обычный метод класса - это неявный динамический метод, который принимает экземпляр как первый аргумент.
Напротив, staticmethod не принимает экземпляр в качестве первого аргумента, поэтому он называется "static".

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

Ответ 26

#!/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()

Ответ 27

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

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