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




11 Answers

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

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




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

@classmethod

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

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

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

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

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

@staticmethod

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

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

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

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

Статические методы в Python аналогичны тем, которые были найдены в Java или C ++. Для более продвинутой концепции см. 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



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

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

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

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

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

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

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



Окончательное руководство по использованию статических, классных или абстрактных методов в 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




метод класса 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

Reference




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

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




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



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



Related