Maison > Article > développement back-end > Explication détaillée de l'utilisation des propriétés du décorateur Python
Le décorateur @property peut transformer une méthode en propriété et l'appeler. Jetons un coup d'œil à l'analyse des compétences d'utilisation du décorateur @property par la magie noire
À quoi sert @property en surface ? Il semble qu'une méthode soit accessible en tant qu'attribut. Le code dans
est le plus clair
class Circle(object): def __init__(self, radius): self.radius = radius @property def area(self): return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area
Vous pouvez voir que bien que la zone soit définie comme une méthode, mais après avoir ajouté @property. , vous pouvez accéder directement à c.area en tant que propriété.
Maintenant, le problème survient, chaque fois que c.area est appelé, il sera calculé une fois, ce qui est un gaspillage de CPU. Comment puis-je le calculer uniquement. once ? Quoi ? C'est la propriété lazy.
class lazy(object): def __init__(self, func): self.func = func def __get__(self, instance, cls): val = self.func(instance) setattr(instance, self.func.__name__, val) return val class Circle(object): def __init__(self, radius): self.radius = radius @lazy def area(self): print 'evalute' return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area print c.area print c.area
Comme vous pouvez le voir, 'evalute' n'est affiché qu'une seule fois, et le mécanisme de @lazy doit être bien compris.
Ici , la classe paresseuse a La méthode __get__ indique qu'il s'agit d'un descripteur Lorsque c.area est exécuté pour la première fois, en raison de problèmes d'ordre, il est d'abord recherché dans c.__dict__. l'espace de classe. Dans la classe Circle, il y a la méthode Area(), elle est donc interceptée par __get__
Dans __get__, appelez la méthode Area() de l'instance pour calculer le résultat, et ajoutez dynamiquement un. attribuez le même nom à l'instance et attribuez-lui le résultat, c'est-à-dire ajoutez-le à Go to c.__dict__.
Lors de l'exécution de c.area, accédez d'abord à c.__dict__, car il a déjà existe en ce moment, vous ne passerez donc pas par la méthode Area() et __get__
Notes
Veuillez faire attention aux scénarios de code suivants :
Extrait de code 1. :
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
Extrait de code 2 :
class Parrot: def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
La différence entre les codes 1 et 2 est que
classe Parrot(objet) :
Sous python2, exécutez le test séparément
Fragment 1 : Une erreur attendue sera demandée Information AttributeError : impossible de définir l'attribut
Fragment 2 : Opération correcte
Reportez-vous au documentation python2, @property fournira une propriété prête à l'emploi, le code ci-dessus ne fournit pas le @voltage.setter correspondant, il va de soi que l'extrait de code 2 provoquera une erreur d'exécution. Dans le document python2, nous pouvons trouver le. informations suivantes :
BIF :
property([fget[, fset[, fdel[, doc]] ]])
Renvoyer un attribut de propriété pour les classes de nouveau style (classes qui dérivent de l'objet).
Il s'avère que sous python2, l'objet de type intégré n'est pas la classe de base par défaut s'il s'agit d'une classe définie, s'il n'y a pas d'explication claire (extrait de code 2). ), le Parrot que nous définissons (extrait de code 2) n'héritera pas de l'objet
et la classe d'objet fournit simplement la fonction @property dont nous avons besoin. Dans le document, vous pouvez trouver les informations suivantes :
classe de nouveau style Toute classe qui hérite d'un objet. Cela inclut tous les types intégrés comme list et dict. Seules les classes de nouveau style peuvent utiliser les fonctionnalités les plus récentes et polyvalentes de Python telles que __slots__, les descripteurs, les propriétés et. __getattribute__().En même temps, nous pouvons également vérifier via la méthode suivanteclass A: pass >>type(A) <type 'classobj'>
class A(object): pass >>type(A) <type 'type'>Retourné de 36f887267d76e0776cc5fd1023a26dbb, 6093e3c6128582bf9e6a58c99d118a2d nous pouvons voir que f5ae6bbdf402bfea04a71faa8c02de77 est le type d'objet dont nous avons besoin (Python 3.0 utilise la classe d'objet comme classe de base par défaut, il renverra donc 2546e8769673d963ba315f1209e3ecc9)Afin de prendre en compte les problèmes de compatibilité pendant la période de transition de la version python du code, je pense que lors de la définition des fichiers de classe, l'objet doit être explicitement défini comme une bonne habitudeEnfin, le code le fera être la suivante :
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage @voltage.setter def voltage(self, new_value): self._voltage = new_value if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12De plus,
@property a été ajouté en 2.6 et 3.0, et la 2.5 n'a pas cette fonction.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!