Maison  >  Article  >  développement back-end  >  Explication détaillée de l'utilisation des propriétés du décorateur Python

Explication détaillée de l'utilisation des propriétés du décorateur Python

巴扎黑
巴扎黑original
2017-08-18 17:11:532205parcourir

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 suivante

class A: 
  pass 
>>type(A) 
<type &#39;classobj&#39;>
class A(object): 
  pass 
>>type(A) 
<type &#39;type&#39;>
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 habitude

Enfin, 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 = 12
De 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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn