Analyse des compétences d'utilisation de la magie noire Python @property decorator

高洛峰
Libérer: 2017-01-23 14:50:32
original
1186 Les gens l'ont consulté

A quoi sert @property ? En apparence, c'est pour accéder à une méthode en tant qu'attribut
Le code 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
Copier après la connexion

<🎜. >

Vous pouvez voir que bien que la zone soit définie comme une méthode, après avoir ajouté @property, vous pouvez directement c.area et y accéder en tant que propriété.

Maintenant, le problème vient, (pas la technologie des excavatrices. Laquelle est la meilleure ), chaque fois que c.area est appelé, il sera calculé une fois, ce qui est un gaspillage de CPU. Comment peut-il être calculé une seule fois ? C'est une propriété paresseuse.

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 &#39;evalute&#39;
    return 3.14 * self.radius ** 2
  
c = Circle(4)
print c.radius
print c.area
print c.area
print c.area
Copier après la connexion

<🎜. >

Comme vous pouvez le voir, 'evalute' n'est affiché qu'une seule fois. Si vous lisez mes articles de blog précédents, vous devriez avoir une bonne compréhension du mécanisme de @lazy

Ici, la classe paresseuse a un __get__. Méthode, expliquant C'est un descripteur. Lorsque c.area a été exécuté pour la première fois, en raison de problèmes d'ordre, il a d'abord été recherché dans c.__dict__. S'il n'a pas été trouvé, il a été recherché dans l'espace de classe. Circle, il existe une méthode Area(), donc c'était __get__ intercepte.

Dans __get__, appelez la méthode Area() de l'instance pour calculer le résultat, et ajoutez dynamiquement un attribut du même nom à l'instance et attribuez le résultat, c'est-à-dire ajoutez-le à c.__dict__.
Lorsque vous exécutez à nouveau c.area, allez d'abord dans c.__dict__, car il existe déjà à ce moment, vous ne passerez donc pas par la zone() method et __get__.

Remarque

Veuillez faire attention aux scénarios de code suivants :


Extrait de code 1 :

Code Python2.6


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
Copier après la connexion

Extrait de code 2 :

Code Python2.6


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
Copier après la connexion

La différence entre les codes 1 et 2 est-ce que

class Parrot(object):
Copier après la connexion

est en python2 6 fois, exécutez les tests séparément

Fragment 1 : un message d'erreur attendu AttributeError : impossible de définir l'attribut sera invité

Fragment 2 : Exécuter correctement

Reportez-vous au document python2.6, @property fournira une propriété prête uniquement. Le code ci-dessus ne fournit pas le @voltage.setter correspondant. dans le fragment 2 provoquera une erreur d'exécution. Dans le document python2.6, nous pouvons trouver les informations suivantes :

BIF :

property([fget[, fset[, fdel[, doc]]] ])

Renvoyer un attribut de propriété pour les classes de nouveau style (classes qui dérivent d'un objet).
À l'origine sous python2.6, l'objet de type intégré n'est pas la classe de base par défaut. lors de la définition de la classe (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 fournira simplement la fonction @property dont nous avons besoin. dans le document :

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__. , descripteurs, propriétés et __getattribute__().


En même temps, nous pouvons également vérifier via les méthodes suivantes

Code Python 2.6


class A:
  pass
 
>>type(A)
<type &#39;classobj&#39;>
Copier après la connexion

Code Python 2.6

class A(object):
  pass
 
>>type(A)
<type &#39;type&#39;>
Copier après la connexion

renvoyé par , on peut voir que est le type d'objet dont nous avons besoin (python 3.0 utilise la classe d'objet comme classe de base par défaut, donc tous renverront

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 du fichier de classe, l'objet doit être explicitement défini comme une bonne habitude

Final Le code sera le suivant :

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
Copier après la connexion

De plus, @property a été ajouté en 2.6 et 3.0, et la 2.5 n'a pas cette fonctionnalité.

Pour plus de conseils de décoration Python sur la magie noire @property et d'articles connexes, veuillez faire attention au site Web PHP chinois !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal