Heim  >  Artikel  >  Backend-Entwicklung  >  Schwierige Verwendung von @property decorator in Python (Codebeispiel)

Schwierige Verwendung von @property decorator in Python (Codebeispiel)

不言
不言nach vorne
2018-11-23 16:45:371732Durchsuche

In diesem Artikel geht es um die technische Verwendung des @property-Dekorators in Python (Codebeispiele). Ich hoffe, dass er für Sie hilfreich ist.

Der @property decorator kann eine Methode in eine Eigenschaft umwandeln und sie aufrufen. Werfen wir einen Blick auf die Analyse der Verwendungsfähigkeiten des @property decorators in Python.

@ Wofür werden Attribute verwendet? ? Oberflächlich betrachtet scheint es, dass auf eine Methode als Attribut zugegriffen wird.

Der obige Code

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

zeigt, dass der Bereich zwar als Methode definiert ist, nach dem Hinzufügen der @-Eigenschaft jedoch direkt auf c.area als Eigenschaft zugegriffen werden kann.

Jetzt kommt das Problem. Jedes Mal, wenn c.area aufgerufen wird, wird es nur einmal berechnet. Das ist die Eigenschaft der Faulheit.

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

Wie Sie sehen, wird „evalute“ nur einmal ausgegeben, daher sollten Sie den Mechanismus von @Lazy gut verstehen.

Hier verfügt die Lazy-Klasse über eine __get__-Methode, die darauf hinweist, dass es sich bei der ersten Ausführung von c.area aufgrund von Auftragsproblemen zunächst um eine Suche in Ç.__dict__ handelt wurde nicht gefunden, gehen Sie einfach zum Klassenraum, um ihn zu finden. Im Klassenkreis gibt es die Methode „area()“, also wird sie von __get__ abgefangen.

Rufen Sie in __get__ die Region()-Methode der Instanz auf, um das Ergebnis zu berechnen, und fügen Sie der Instanz dynamisch ein Attribut mit demselben Namen hinzu und weisen Sie ihr das Ergebnis zu, dh fügen Sie es zu Ç hinzu. __ dict__.

Wenn Sie c.area erneut ausführen, gehen Sie zuerst zu Ç.__ dict__, um es zu finden, da es zu diesem Zeitpunkt bereits existiert, sodass Sie nicht die Methode „area()“ und „__get__“ durchlaufen müssen.

Hinweise

Bitte beachten Sie folgende Code-Szenarien:

Code-Schnipsel 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

Code-Schnipsel 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

Code 1, der Unterschied zwischen 2 ist

Klasse Parrot (Objekt):

Führen Sie den Test unter Python2 separat aus

Fragment 1: Eine erwartete Fehlermeldung AttributeError: Unable to werden aufgefordert, die Eigenschaft festzulegen

Fragment 2: Korrekt ausführen

Siehe die Python2-Dokumentation, die ein schreibgeschütztes Attribut bereitstellt Es liegt auf der Hand, dass der Code in Fragment 2 zu einem Fehler beim Ausführen führt. In der Python2-Dokumentation finden wir die folgenden Informationen:

BIF:

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

Gibt die Attributeigenschaften der neuen Stilklasse zurück (von Object abgeleitete Klassen).

Es stellt sich heraus, dass unter Python2 das integrierte Typobjekt nicht die Standardbasisklasse ist. Wenn es beim Definieren der Klasse (Code-Snippet 2) keine klare Erklärung gibt, wird der von uns definierte Parrot (Code-Snippet 2) verwendet ) erbt kein Objekt

Die Objektklasse stellt lediglich die @property-Funktion bereit, die wir benötigen. Wir können die folgenden Informationen im Dokument finden:

Neue Stilklasse

Jede Klasse das erbt von object . Dazu gehören alle integrierten Typen wie list und dict. Nur Klassen neuen Stils können die neueren, generischen Funktionen von Python wie __slots__, Deskriptoren, Attribute und __getattribute__() verwenden.

Gleichzeitig können wir dies auch mit der folgenden Methode überprüfen

class A: 
  pass 
>>type(A) 
<type &#39;classobj&#39;>
class A(object): 
  pass 
>>type(A) 
<type &#39;type&#39;>

Aus dem zurückgegebenen , ist der Objekttyp, den wir benötigen (Python 3.0 verwendet die Objektklasse als Standardbasisklasse, daher werden alle ) zurückgeben.

Um zu berücksichtigen Frage zur Kompatibilität der Python-Version Übergangszeit des Codes: Ich denke, dass Objekte beim Definieren von Klassendateien explizit definiert werden sollten.

Der endgültige Code wird wie folgt aussehen:

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

Das obige ist der detaillierte Inhalt vonSchwierige Verwendung von @property decorator in Python (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen