Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung der Eigenschaftsverwendung des Python-Dekorators

Detaillierte Erläuterung der Eigenschaftsverwendung des Python-Dekorators

巴扎黑
巴扎黑Original
2017-08-18 17:11:532205Durchsuche

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

Was ist der Nutzen von @property? Es scheint, dass auf eine Methode als Attribut zugegriffen wird.

Sie können sehen, dass der Bereich zwar als Methode definiert ist, aber nach dem Hinzufügen von @property , Sie können direkt auf c.area als Eigenschaft zugreifen

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
Jetzt tritt das Problem auf, dass jedes Mal, wenn c.area aufgerufen wird, es einmal berechnet wird, was eine Verschwendung von CPU ist einmal? Was? Das ist die Lazy-Eigenschaft.

Wie Sie sehen können, wird „evalute“ nur einmal ausgegeben, und der Mechanismus von @lazy sollte gut verstanden werden.

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
Hier Die Lazy-Klasse weist darauf hin, dass es sich bei der ersten Ausführung von c.area um einen Deskriptor handelt. Wenn dieser nicht gefunden wird, wird er aufgrund von Auftragsproblemen durchsucht Im Klassenraum gibt es die Methode „area( )“, also wird sie von __get__ abgefangen. Rufen Sie in __get__ die Methode „area()“ der Instanz auf und fügen Sie dynamisch eine hinzu Attribut mit demselben Namen zur Instanz und weisen Sie ihr das Ergebnis zu, das heißt, fügen Sie es zu Gehe zu c.__dict__ hinzu.

Wenn Sie c.area erneut ausführen, gehen Sie zuerst zu c.__dict__, da es bereits vorhanden ist existiert zu diesem Zeitpunkt, daher werden Sie die Methode „area()“ und __get__ nicht durchlaufen.

Hinweise

Bitte beachten Sie die folgenden Codeszenarien:

Codeausschnitt 1 :

Codeausschnitt 2:

Der Unterschied zwischen Code 1 und 2 besteht darin, dass
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

Klasse Parrot(object):

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
Führen Sie den Test unter Python2 separat aus

Fragment 1: Ein erwarteter Fehler wird angezeigt. Information AttributeError: Attribut kann nicht festgelegt werden

Fragment 2: Korrekter Vorgang

Siehe In der Python2-Dokumentation stellt @property eine schreibgeschützte Eigenschaft bereit. Der obige Code stellt den entsprechenden @length.setter nicht bereit. Es liegt auf der Hand, dass der Snippet-2-Code einen laufenden Fehler auslöst. Im Python2-Dokument können wir Folgendes finden Folgende Informationen:

BIF:

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

Gibt ein Eigenschaftsattribut für Klassen neuen Stils zurück (Klassen, die von Objekt abgeleitet sind).

Es stellt sich heraus, dass unter Python2 der integrierte Typ Objekt nicht die Standardbasisklasse ist, wenn es keine klare Erklärung gibt (Codeausschnitt 2 ), erbt der von uns definierte Parrot (Codeausschnitt 2) kein Objekt

und die Objektklasse stellt nur die @property-Funktion bereit, die wir benötigen. Im Dokument finden Sie die folgenden Informationen:

Klasse im neuen Stil

Jede Klasse, die von Objekt erbt. Dazu gehören alle integrierten Typen wie Liste und Diktat. Nur Klassen im neuen Stil können die neueren, vielseitigen Funktionen von Python wie __slots__, Deskriptoren und Eigenschaften verwenden __getattribute__().

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

Zurückgegeben von 36f887267d76e0776cc5fd1023a26dbb, 6093e3c6128582bf9e6a58c99d118a2d können wir sehen, dass f5ae6bbdf402bfea04a71faa8c02de77 der Objekttyp ist, den wir benötigen (Python 3.0 verwendet die Objektklasse als Standardbasisklasse, daher wird f5ae6bbdf402bfea04a71faa8c02de77 zurückgegeben)

Um die Kompatibilitätsprobleme während der Übergangsphase der Python-Version des Codes zu berücksichtigen, denke ich, dass bei der Definition von Klassendateien das Objekt explizit als gute Angewohnheit definiert werden sollte
class A: 
  pass 
>>type(A) 
<type &#39;classobj&#39;>
class A(object): 
  pass 
>>type(A) 
<type &#39;type&#39;>
Schließlich wird der Code wie folgt sein:

Außerdem wurde

@property in 2.6 und 3.0 hinzugefügt, und 2.5 verfügt nicht über diese Funktion.

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Eigenschaftsverwendung des Python-Dekorators. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn