Python-Deskriptoren sind eine Möglichkeit, verwaltete Eigenschaften zu erstellen. Immer wenn ein Attribut abgefragt wird, wird eine Aktion ausgeführt. Diese Aktion ist standardmäßig „Abrufen“, „Festlegen“ oder „Löschen“. Manchmal stellt eine Anwendung jedoch
mehr Anforderungen und erfordert, dass Sie einige komplexere Aktionen entwerfen. Die beste Lösung besteht darin, eine Funktion zu schreiben, die die gewünschte Aktion ausführt, und dann anzugeben, dass sie ausgeführt wird, wenn auf die Eigenschaft zugegriffen wird. Ein Objekt
mit dieser Funktionalität wird als Deskriptor bezeichnet. Deskriptoren sind die Grundlage für die Implementierung von Python-Methoden, gebundenen Methoden, Super, PRperty, Staticmethod und Classmethod.
1. Deskriptorprotokoll
Ein Deskriptor ist ein Objekt, das einen Attributwert darstellt. Durch die Implementierung einer oder mehrerer Methoden __get__, __set__, __delete__ kann auf den Deskriptor und die Attribute zugegriffen werden Diese Vorgänge können auch individuell angepasst werden.
__get__(selbst, Instanz, eigener): Wird verwendet, um auf Attribute zuzugreifen und den Wert des Attributs zurückzugeben. „Instance“ ist das Instanzobjekt, das den Deskriptor verwendet, und „own“ ist die Klasse, zu der die Instanz gehört. Beim Zugriff auf eine Eigenschaft über eine Klasse ist die Instanz „None“.
__set__(selbst, Instanz, Wert): Attributwert festlegen.
__delete__(self,instance): Attributwert löschen.
2. So implementieren Sie Deskriptoren
Klassendeskriptor (Objekt): Print 'Deleting:%s'%Self._name >> del p.name Wenn __get__ und __set__ implementiert sind, handelt es sich um einen Datendeskriptor. Wenn nur __get__ implementiert ist, handelt es sich um einen Nicht-Daten-Deskriptor. Der unterschiedliche Effekt besteht darin, dass der Datendeskriptor immer die Attributimplementierung in einer Instanz ersetzt und der Nicht-Datendeskriptor keinen Satz hat, wenn Attributen über die Instanz Werte zugewiesen werden, wie oben p.name = 'hello', die Methode __set__ wird nicht mehr aufgerufen und das Instanzattribut p.name wird direkt auf 'hello' gesetzt. Wenn Sie AttributeError nur in __set__ auslösen, erhalten Sie natürlich immer noch einen Nicht-Daten-Deskriptor. Deskriptor-Aufrufmechanismus: Wenn Python beim Abfragen des Attributs a.attr eines Objekts feststellt, dass attr ein Deskriptorobjekt ist, hängt das Lesen des Attributs vom Objekt a ab: Direkter Aufruf: Der einfachste Aufruf besteht darin, den Code direkt zum Aufrufen der Deskriptormethode attr.__get__(a) zu verwenden Instanzbindung: Wenn a ein Instanzobjekt ist, rufen Sie die Methode auf: type( a).__dict__ ['attr'].__get__(a,type(a)) Klassenbindung: Wenn A ein Klassenobjekt ist, rufen Sie die Methode auf: A.__dict__['attr'].__get__( None,A) Superbindung: Wenn a eine Superinstanz ist, dann findet super(B,obj).m() die Basisklasse A von B durch Abfrage von obj.__class__.__mro__ und führt dann A.__dict__ aus ['m' ].__get__(obj,obj.__class__) 3. Deskriptor, der die Attributtypprüfung durchführt class TypedProperty(object): Und das Löschen von Attributen ist verboten: f.name unsichtbarer Aufruftyp(f).__dict__['name ']. __get__(f,Foo), also Foo.name.__get__(f,Foo). Andernfalls kollidiert der Deskriptorname name mit dem Instanzattributnamen und das Deskriptorattribut f.name überschreibt das Instanzattribut f.name. Das Obige ist der Inhalt des Python-Deskriptors (1). Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!
def __get__(selbst, Instanz, Besitzer):
print 'getting:%s'%self. _Name
DEF __SET __ (Selbst, Instanz, Name):
Print'-Einstellung:%s'%name
Self._name = Name
stance ):
Del Self._name
Class Person (Object):
name = descriptionor ()
Ein sehr einfaches Deskriptorobjekt wird generiert. Jetzt können Sie den Attributnamen eines Personenobjekts lesen, festlegen und löschen:
Hinweis: Deskriptoren können nur auf Klassenebene instanziiert werden und können nicht für jedes Deskriptorobjekt in __init__() und anderen Methoden zur Instanzerstellung erstellt werden.
Eigenschaftsnamen, die von Klassen mit Deskriptoren verwendet werden, haben eine höhere Priorität als in Instanzen gespeicherte Eigenschaftsnamen. Damit ein Deskriptor einen Wert auf einer Instanz speichern kann, muss der Deskriptor einen Namen auswählen, der sich von dem Namen unterscheidet, den er selbst verwendet.
Wie im obigen Beispiel kann die Person-Klasseninitialisierungsfunktion __init__ den Namen nicht zum Festlegen von Attributen für die Instanz verwenden.
Datendeskriptor und Nicht-Daten-Deskriptor:
def __init__(self,name,attr_type,default=None):
self.name='_'+name
self.type=attr_type
self .default=default if default else attr_type()
def __get__(self,instance,own):
return getattr(instance,self.name,self.default)
def __set__(self,instance,value ):
if not isinstance(value,self.type):
raise TypeError,'Must be %s'%self.type
setattr(instance,self.name,value)
def __delete__ (self,instance):
raise AttributeError('Attribut kann nicht gelöscht werden')
class Foo(object):
name=TypedProperty('name',str)
num=TypedProperty('num ',int,37) & auf den Typ int gesetzt, ein Fehler wird gemeldet:
>>> f.name=21
>>> del f.name
Der obige Deskriptor wird tatsächlich auf f._name über setattr(f,_name,value) gespeichert, und num wird auf f._num gespeichert.