статические - staticmethod vs classmethod python




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

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

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


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

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


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


Еще одно соображение относительно метода 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


Мой вклад демонстрирует разницу между @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'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)
'''
"""

Позвольте мне сказать сходство между методом, украшенным с помощью метода @classmethod vs @staticmethod.

Сходство: оба они могут быть вызваны самим классом , а не только экземпляром класса. Итак, оба они в некотором смысле являются методами Класса .

Разница: класс-метод получит сам класс как первый аргумент, в то время как 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',)

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

@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

и вы можете просто вызвать имя класса

Person.validate_name("Gaurang Shah")

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

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

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


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

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

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

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

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

Официальные документы 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 ().

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

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

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

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

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

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

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


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

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




python-decorators