Objektdeskriptor
Im Allgemeinen ist ein Deskriptor ein Objektattribut mit ?Bindungsverhalten“ und seine Zugriffskontrolle wird durch die Methoden des Deskriptorprotokolls au?er Kraft gesetzt. Diese Methoden sind __get__(), __set__() und __delete__(). Objekte mit diesen Methoden werden Deskriptoren genannt.
Die Standardzugriffskontrolle für Attribute besteht darin, aus dem W?rterbuch des Objekts (__dict__) abzurufen (get), festzulegen (set) und zu l?schen (delete). Die Suchreihenfolge für a.x lautet beispielsweise: a.__dict__['x'], geben Sie dann (a).__dict__['x'] ein und suchen Sie dann die übergeordnete Klasse von Typ (a) (ohne Metaklasse). Wenn die Wenn der gefundene Wert ein Deskriptor ist, ruft Python die Methoden des Deskriptors auf, um das Standardverhalten der Steuerung zu überschreiben. Wo in der Suchphase dieses überschreiben auftritt, h?ngt davon ab, welche Deskriptormethode definiert ist. Beachten Sie, dass Deskriptoren nur innerhalb einer Klasse neuen Stils funktionieren. Klassen neuen Stils und Klassen alten Stils wurden in den vorherigen Kapiteln erw?hnt. Wenn Sie interessiert sind, k?nnen Sie sich die vorherigen Kapitel ansehen. Das gr??te Merkmal von Klassen neuen Stils ist, dass alle Klassen von Typ- oder Objektklassen erben.
Wenn bei der objektorientierten Programmierung die Attribute einer Klasse voneinander abh?ngig sind, kann die Verwendung von Deskriptoren zum Schreiben von Code die Logik sehr geschickt organisieren. Im ORM von Django implementieren Felder wie InterField in models.Model ihre Funktionen über Deskriptoren.
Schauen wir uns zun?chst das folgende Beispiel an:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class User(object): def __init__(self, name='兩點(diǎn)水', sex='男'): self.sex = sex self.name = name def __get__(self, obj, objtype): print('獲取 name 值') return self.name def __set__(self, obj, val): print('設(shè)置 name 值') self.name = val class MyClass(object): x = User('兩點(diǎn)水', '男') y = 5 if __name__ == '__main__': m = MyClass() print(m.x) print('\n') m.x = '三點(diǎn)水' print(m.x) print('\n') print(m.x) print('\n') print(m.y)
Das Ausgabeergebnis lautet wie folgt:
獲取 name 值 兩點(diǎn)水 設(shè)置 name 值 獲取 name 值 三點(diǎn)水 獲取 name 值 三點(diǎn)水 5
Anhand dieses Beispiels k?nnen Sie __get__() und gut beobachten _ _set__() Aufrufe dieser Methoden.
Schauen Sie sich ein weiteres klassisches Beispiel an
Wir wissen, dass Entfernungen in der Einheit ?Meter“ oder ?Fu?“ ausgedrückt werden k?nnen. Jetzt definieren wir eine Klasse zur Darstellung der Entfernung, die zwei Eigenschaften hat: Meter und Fu?.
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class Meter(object): def __init__(self, value=0.0): self.value = float(value) def __get__(self, instance, owner): return self.value def __set__(self, instance, value): self.value = float(value) class Foot(object): def __get__(self, instance, owner): return instance.meter * 3.2808 def __set__(self, instance, value): instance.meter = float(value) / 3.2808 class Distance(object): meter = Meter() foot = Foot() if __name__ == '__main__': d = Distance() print(d.meter, d.foot) d.meter = 1 print(d.meter, d.foot) d.meter = 2 print(d.meter, d.foot)
Ausgabeergebnis:
0.0 0.0 1.0 3.2808 2.0 6.5616
Im obigen Beispiel denken wir, dass Meter und Fu? Instanzobjekte ihrer jeweiligen Klassen sein sollten, bevor wir der Instanz von Distance einen Wert zuweisen, aber die Ausgabe ist ein numerischer Wert. Das liegt daran, dass __get__ eine Rolle spielt.
Wir haben gerade meter ge?ndert und es int zugewiesen, aber auch foot wurde ge?ndert. Hier kommt __set__ ins Spiel.
Das Deskriptorobjekt (Meter, Foot) kann nicht unabh?ngig existieren, es muss von einer anderen Besitzerklasse (Distance) gehalten werden. Das Deskriptorobjekt kann auf die Eigenschaften seiner Eigentümerinstanz zugreifen, im Beispiel beispielsweise auf ?instance.meter“ von ?Foot“.