[Python] Signification de @classmethod et @staticmethod pour débutant?


Answers

La réponse de Rostyslav Dzinko est très appropriée. J'ai pensé que je pourrais mettre en évidence une autre raison pour laquelle vous devriez choisir @classmethod sur @staticmethod lorsque vous créez un constructeur supplémentaire.

Dans l'exemple ci-dessus, Rostyslav a utilisé la @classmethod from_string tant from_string pour créer des objets Date partir de paramètres non acceptables. La même chose peut être faite avec @staticmethod comme indiqué dans le code ci-dessous:

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

Par conséquent, new_year et millenium_new_year sont des instances de la classe Date .

Mais, si vous observez de près, le processus Factory est codé en dur pour créer des objets Date , quoi qu'il arrive. Cela signifie que même si la classe Date est sous-classée, les sous-classes créeront toujours un objet Date simple (sans aucune propriété de la sous-classe). Voir dans l'exemple ci-dessous:

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 n'est pas une instance de DateTime ? WTF? Eh bien, c'est à cause du décorateur @staticmethod utilisé.

Dans la plupart des cas, cela n'est pas souhaitable. Si ce que vous voulez est une méthode Factory qui est consciente de la classe qui l'a appelée, alors @classmethod est ce dont vous avez besoin.

Réécriture du Date.millenium tant que (c'est la seule partie du code ci-dessus qui change)

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

s'assure que la class n'est pas codée en dur mais plutôt apprise. cls peut être n'importe quelle sous-classe. L' object résultant sera à juste titre une instance de cls . Testons ça.

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"

La raison en est, comme vous le savez maintenant, @classmethod été utilisé à la place de @staticmethod

Question

Quelqu'un pourrait-il m'expliquer la signification de @classmethod et @staticmethod en python? J'ai besoin de connaître la différence et le sens.

Autant que je comprends, @classmethod dit à une classe que c'est une méthode qui devrait être héritée dans les sous-classes, ou ... quelque chose. Cependant, quel est le point de cela? Pourquoi ne pas simplement définir la méthode de classe sans ajouter @classmethod ou @staticmethod ou aucune @ définition?

tl; dr: quand devrais-je les utiliser, pourquoi devrais-je les utiliser, et comment dois-je les utiliser?

Je suis assez avancé avec C ++, donc l'utilisation de concepts de programmation plus avancés ne devrait pas poser de problème. N'hésitez pas à me donner un exemple C ++ correspondant si possible.




@staticmethod fonction @staticmethod n'est rien de plus qu'une fonction définie dans une classe. Il est appelable sans instancier la classe en premier. Sa définition est immuable via l'héritage.

  • Python n'a pas besoin d'instancier une méthode liée pour l'objet.
  • Cela facilite la lisibilité du code: en voyant @staticmethod , on sait que la méthode ne dépend pas de l'état de l'objet lui-même;

@classmethod fonction @classmethod est également appelable sans instancier la classe, mais sa définition suit la classe Sub, pas la classe Parent, via l'héritage, peut être surchargée par la sous-classe. C'est parce que le premier argument de la fonction @classmethod doit toujours être cls (class) .

  • Les méthodes d'usine , qui sont utilisées pour créer une instance pour une classe en utilisant par exemple une sorte de pré-traitement.
  • Méthodes statiques appelant des méthodes statiques : si vous divisez une méthode statique en plusieurs méthodes statiques, vous ne devez pas coder en dur le nom de la classe, mais utiliser des méthodes de classe

here bon lien vers ce sujet.




Je suis un débutant sur ce site, j'ai lu toutes les réponses ci-dessus, et j'ai obtenu l'information que je veux. Cependant, je n'ai pas le droit d'upvote. Donc, je veux commencer sur avec la réponse telle que je la comprends.

  • @staticmethod n'a pas besoin de self ou de cls comme premier paramètre de la méthode
  • @staticmethod et @classmethod peut être appelée par une instance ou une variable de classe
  • @staticmethod fonction décorée @staticmethod impact sur une sorte de 'propriété immuable' que l'héritage de sous-classe ne peut pas écraser sa fonction de classe de base qui est enveloppée par un décorateur @staticmethod .
  • @classmethod need cls (Nom de la classe, vous pouvez changer le nom de la variable si vous le souhaitez, mais ce n'est pas conseillé) comme premier paramètre de la fonction
  • @classmethod toujours utilisé par sous-classe, l'héritage de sous-classe peut changer l'effet de la fonction de classe de base, ie la fonction de classe de base enveloppée par @classmethod pourrait être écrasée par différentes sous-classes.



J'ai essayé d'écrire un exemple simple pour montrer la différence entre l'utilisation de staticmethod et classmethod (et aussi de ne pas les utiliser). Voici le code:

#without decorator:
class Duck(object):
    def sound(self):
        print("Quack")


#pay attention to the "sound" function:

#with @staticmethod
class Cat(object):
    @staticmethod
    def sound():
        print("Meow")

#with @classmethod
class Dog(object):
    @classmethod
    def sound(self):
        print("woof")


#notice the differences between calling them:
Duck().sound()
Cat.sound()
Dog.sound()

#prints:
"""
Quack
Meow
woof
"""



La méthode Class peut modifier l'état de la classe, elle est liée à la classe et contient cls comme paramètre.

La méthode statique ne peut pas modifier l'état de la classe, elle est liée à la classe et ne connaît pas la classe ou l'instance

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)



On pourrait utiliser @classmethod quand il / elle voudrait changer le comportement de la méthode en fonction de la sous-classe qui appelle la méthode. rappelez-vous que nous avons une référence à la classe appelante dans une méthode de classe.

Tout en utilisant statique, vous souhaitez que le comportement reste inchangé à travers les sous-classes

Exemple:

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..."