Значение @classmethod и @staticmethod для начинающих?

Может ли кто-нибудь объяснить мне смысл @classmethod и @staticmethod в python? Мне нужно знать разницу и смысл.

Насколько я понимаю, @classmethod сообщает классу, что это метод, который должен быть унаследован в подклассы или … что-то. Однако в чем смысл? Почему бы просто не определить метод класса без добавления @classmethod или @staticmethod или любых @ определений?

tl; dr: когда следует использовать их, почему я должен их использовать и как их использовать?

Я довольно продвинутый с C ++, поэтому использование более продвинутых концепций программирования не должно быть проблемой. Не стесняйтесь давать мне соответствующий C ++-пример, если это возможно.

9 Solutions collect form web for “Значение @classmethod и @staticmethod для начинающих?”

Хотя classmethod и staticmethod очень похожи, есть небольшая разница в использовании для обоих объектов: classmethod должен иметь ссылку на объект класса в качестве первого параметра, тогда как staticmethod может иметь никаких параметров вообще.

Давайте посмотрим на все, что было сказано в реальных примерах.

Boilerplate

Давайте предположим пример класса, касающегося информации о дате (это будет наш шаблон для приготовления пищи):

 class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year 

Этот класс, очевидно, может использоваться для хранения информации о некоторых датах (без информации о часовом поясе, давайте предположим, что все даты представлены в формате UTC).

Здесь у нас есть __init__ , типичный инициализатор экземпляров класса Python, который получает аргументы как типичный метод instancemethod , имеющий первый необязательный аргумент ( self ), который содержит ссылку на вновь созданный экземпляр.

Метод класса

У нас есть некоторые задачи, которые можно выполнить с помощью classmethod .

Предположим, что мы хотим создать много экземпляров класса Date имеющих информацию о дате, поступающую из внешнего источника, закодированную в виде строки следующего формата ('dd-mm-yyyy'). Мы должны сделать это в разных местах нашего исходного кода в проекте.

Итак, что мы должны сделать здесь:

  1. Разбирайте строку, чтобы получать день, месяц и год в виде трех целых переменных или 3-элементного кортежа, состоящего из этой переменной.
  2. Создайте Date , передав эти значения для вызова инициализации.

Это будет выглядеть так:

 day, month, year = map(int, string_date.split('-')) date1 = Date(day, month, year) 

С этой целью C ++ имеет такую ​​функцию, как перегрузка, но Python не хватает этой функции, поэтому здесь применяется classmethod . Давайте создадим еще один « конструктор ».

  @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 date2 = Date.from_string('11-09-2012') 

Давайте посмотрим более внимательно на вышеупомянутую реализацию и рассмотрим, какие преимущества у нас есть здесь:

  1. Мы провели синтаксический анализ строк даты в одном месте и теперь снова можно использовать повторно.
  2. Инкапсуляция отлично работает здесь (если вы считаете, что вы можете реализовать синтаксический анализ строк как одну функцию в другом месте, это решение намного лучше подходит для OOP-парадигмы).
  3. cls – объект, который содержит сам класс , а не экземпляр класса. Это довольно круто, потому что, если мы наследуем наш класс Date , все дочерние from_string также будут иметь from_string .

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

Как насчет staticmethod ? Он очень похож на classmethod но не принимает никаких обязательных параметров (например, метод класса или метод экземпляра).

Давайте посмотрим на следующий пример использования.

У нас есть строка даты, которую мы хотим как-то проверить. Эта задача также логически связана с классом Date мы использовали до сих пор, но все еще не требует его создания.

Вот где staticmethod может быть полезным. Давайте посмотрим на следующий фрагмент кода:

  @staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 # usage: is_date = Date.is_date_valid('11-09-2012') 

Таким образом, как мы видим из использования staticmethod , у нас нет никакого доступа к тому, что является классом, – это в основном просто функция, называемая синтаксически подобной методу, но без доступа к объекту и его внутренним элементам (полям и другим методам ), в то время как classmethod делает.

Ответ Ростислава Дзинько очень уместен. Я думал, что могу выделить еще одну причину, по которой вам следует выбрать @classmethod над @staticmethod когда вы создаете дополнительный конструктор.

В приведенном выше примере Ростислав использовал @classmethod from_string как Factory для создания объектов Date из неприемлемых других параметров. То же самое можно сделать с помощью @staticmethod как показано в приведенном ниже коде:

 class Date: def __init__(self, month, day, year): self.month = month self.day = day self.year = year def display(self): return "{0}-{1}-{2}".format(self.month, self.day, self.year) @staticmethod def millenium(month, day): return Date(month, day, 2000) new_year = Date(1, 1, 2013) # Creates a new Date object millenium_new_year = Date.millenium(1, 1) # also creates a Date object. # Proof: new_year.display() # "1-1-2013" millenium_new_year.display() # "1-1-2000" isinstance(new_year, Date) # True isinstance(millenium_new_year, Date) # True 

Таким образом, new_year и millenium_new_year являются экземплярами класса Date .

Но, если вы внимательно наблюдаете, процесс Factory жестко закодирован для создания объектов Date независимо от того, что. Это означает, что даже если класс Date является подклассом, подклассы будут по-прежнему создавать простой объект Date (без какого-либо свойства подкласса). Посмотрите, что в следующем примере:

 class DateTime(Date): def display(self): return "{0}-{1}-{2} - 00:00:00PM".format(self.month, self.day, self.year) datetime1 = DateTime(10, 10, 1990) datetime2 = DateTime.millenium(10, 10) isinstance(datetime1, DateTime) # True isinstance(datetime2, DateTime) # False datetime1.display() # returns "10-10-1990 - 00:00:00PM" datetime2.display() # returns "10-10-2000" because it's not a DateTime object but a Date object. Check the implementation of the millenium method on the Date class 

datetime2 не является экземпляром DateTime ? WTF? Ну, это из-за @staticmethod декоратора @staticmethod .

В большинстве случаев это нежелательно. Если вы хотите, это метод Factory, который знает класс, который его назвал, тогда @classmethod – это то, что вам нужно.

Переписывание Date.millenium как (это единственная часть вышеприведенного кода, который изменяется)

 @classmethod def millenium(cls, month, day): return cls(month, day, 2000) 

гарантирует, что class не жестко закодирован, а скорее изучен. cls может быть любым подклассом. Результирующий object праву будет экземпляром cls . Давайте проверим это.

 datetime1 = DateTime(10, 10, 1990) datetime2 = DateTime.millenium(10, 10) isinstance(datetime1, DateTime) # True isinstance(datetime2, DateTime) # True datetime1.display() # "10-10-1990 - 00:00:00PM" datetime2.display() # "10-10-2000 - 00:00:00PM" 

Причина в том, что, как вы знаете, теперь @classmethod использовался вместо @staticmethod

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

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

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

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

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

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

вот хорошая ссылка на эту тему.

Можно было бы использовать @classmethod когда он / она захочет изменить поведение метода, основываясь на том, какой подкласс вызывает метод. помните, что у нас есть ссылка на вызывающий класс в методе класса.

При использовании static вы хотели бы, чтобы поведение оставалось неизменным по подклассам

Пример:

 class Hero: @staticmethod def say_hello(): print("Helllo...") @classmethod def say_class_hello(cls): if(cls.__name__=="HeroSon"): print("Hi Kido") elif(cls.__name__=="HeroDaughter"): print("Hi Princess") class HeroSon(Hero): def say_son_hello(self): print("test hello") class HeroDaughter(Hero): def say_daughter_hello(self): print("test hello daughter") testson = HeroSon() testson.say_class_hello() #Output: "Hi Kido" testson.say_hello() #Outputs: "Helllo..." testdaughter = HeroDaughter() testdaughter.say_class_hello() #Outputs: "Hi Princess" testdaughter.say_hello() #Outputs: "Helllo..." 

Небольшая компиляция

@staticmethod Способ записи метода внутри класса без ссылки на объект, на который он вызывается. Поэтому нет необходимости передавать неявный аргумент, например self или cls. Это написано точно так же, как написано вне класса, но это не бесполезно для python, потому что если вам нужно инкапсулировать метод внутри класса, так как этот метод должен быть частью этого класса, то метод @staticmethod удобен в том, что дело.

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

Сравнение этих двух методов может быть следующим:

Таблица

Немного другой способ подумать об этом, который может быть полезен для кого-то … Метод класса используется в суперклассе для определения того, как должен вести себя этот метод, когда он вызывается разными дочерними классами. Статический метод используется, когда мы хотим вернуть одно и то же, независимо от дочернего класса, который мы вызываем.

Я новичок на этом сайте, я прочитал все вышеперечисленные ответы и получил информацию, что хочу. Однако у меня нет права на повышение. Поэтому я хочу начать с StackOverflow с ответа, насколько я понимаю.

  • @staticmethod не нуждается в self или cls в качестве первого параметра метода
  • @staticmethod и @classmethod может быть вызвана переменной экземпляра или класса
  • @staticmethod украшенные функции влияют на какое-то «неизменяемое свойство», что наследование подкласса не может перезаписывать его функцию базового класса, которая обертывается декоратором @staticmethod .
  • @classmethod need cls (Имя класса, вы можете изменить имя переменной, если хотите, но это не рекомендуется) в качестве первого параметра функции
  • @classmethod всегда используется подклассовым способом, наследование подкласса может изменить эффект функции базового класса, т. е. функция классного класса, обернутая @classmethod может быть перезаписана разными подклассами.

Метод класса может модифицировать состояние класса, он связан с классом и содержит параметр cls в качестве параметра.

Статический метод не может изменять состояние класса, он связан с классом, и он не знает класс или экземпляр

 class empDetails: def __init__(self,name,sal): self.name=name self.sal=sal @classmethod def increment(cls,name,none): return cls('yarramsetti',6000 + 500) @staticmethod def salChecking(sal): return sal > 6000 emp1=empDetails('durga prasad',6000) emp2=empDetails.increment('yarramsetti',100) # output is 'durga prasad' print emp1.name # output put is 6000 print emp1.sal # output is 6500,because it change the sal variable print emp2.sal # output is 'yarramsetti' it change the state of name variable print emp2.name # output is True, because ,it change the state of sal variable print empDetails.salChecking(6500) 
Python - лучший язык программирования в мире.