Вопрос

В чем разница между функцией, украшенной @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:

@classmethod

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

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

А @classmethod форма - это функция декоратор - См. Описание определений функций в Определения функций для получения подробной информации.

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

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

@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 не использует состояние объекта.Это может быть внешняя по отношению к классу функция.Внутри класса он помещается только для группировки функций со схожей функциональностью (например, как в 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):
        return atan(y, x)


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

angle = Point.angle(3, 2)

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top