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='两点水', sex='男'): self.sex = sex self.name = name def __get__(self, obj, objtype): print('获取 name 值') return self.name def __set__(self, obj, val): print('设置 name 值') self.name = val class MyClass(object): x = User('两点水', '男') y = 5 if __name__ == '__main__': m = MyClass() print(m.x) print('\n') m.x = '三点水' print(m.x) print('\n') print(m.x) print('\n') print(m.y)
Das Ausgabeergebnis lautet wie folgt:
获取 name 值 两点水 设置 name 值 获取 name 值 三点水 获取 name 值 三点水 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“.