2014-09-12 7 views
6

Was sind einige allgemeine Faustregeln für die Auswahl, welche von diesen in einer bestimmten Klasse in einer bestimmten Situation zu implementieren?Was sind einige Faustregeln für die Entscheidung zwischen __get__, __getattr__ und __getattribute__?

Ich habe die Dokumente gelesen, und verstehe so den Unterschied zwischen ihnen. Ich suche vielmehr nach Hinweisen, wie ich ihre Verwendung am besten in meinen Workflow integrieren kann, indem ich subtilere Möglichkeiten erkennen kann, sie zu nutzen und wann sie zu verwenden sind. Derartiges. Die Verfahren in Frage sind (meines Wissens):

## fallback 
__getattr__ 
__setattr__ 
__delattr__ 

## full control 
__getattribute__ 
##(no __setattribute__ ? What's the deal there?) 

## (the descriptor protocol) 
__get__ 
__set__ 
__delete__ 
+1

Zum Close-Voter: IMX, Lernerfragen wie "Wie entscheide ich mich zwischen X und Y?" oder "Was ist der Unterschied zwischen X und Y?" sind wirklich zwei Fragen - "Was ist der beabsichtigte Zweck von X?" und "Was ist der beabsichtigte Zweck von Y?" Vielleicht wäre es besser, sie getrennt zu fragen, aber im aktuellen Fall ist auch keine "zu weite" IMO, und es besteht zumindest eine gewisse Verbindung zwischen den verschiedenen magischen Methoden. –

Antwort

5

__setattribute__ existiert nicht, weil __setattr__immer genannt wird. __getattr__ wird nur für f.x aufgerufen, wenn die Attributsuche über den normalen Kanal fehlschlägt (der von __getattribute__ bereitgestellt wird, so dass die Funktion in ähnlicher Weise immer aufgerufen wird).

Das Deskriptorprotokoll ist leicht orthogonal zu den anderen.Angesichts

class Foo(object): 
    def __init__(self): 
     self.x = 5 

f = Foo() 

folgenden Bedingungen erfüllt sind:

  • f.xf.__getattribute__('x') aufrufen würde, wenn sie definiert wurden.
  • f.x würde f.__getattr__('x') nicht aufrufen, wenn es definiert wäre.
  • f.y würde f.__getattr__('y') berufen, wenn sie definiert wurden, oder auch f.__getattribute__('y') wenn es definiert wurden.

Der Deskriptor aufgerufen wird durch ein Attribut, anstatt für ein Attribut. Das heißt:

class MyDescriptor(object): 
    def __get__(...): 
     pass 
    def __set__(...): 
     pass 

class Foo(object): 
    x = MyDescriptor() 

f = Foo() 

Nun f.x verursachen würde type(f).__dict__['x'].__get__ genannt zu werden, und f.x = 3 würde type(f).__dict__['x'].__set__(3) nennen.

Das heißt, Foo.__getattr__ und Foo.__getattribute__ würde verwendet werden, um herauszufinden, was f.xReferenzen; Sobald Sie das haben, f.x erzeugt das Ergebnis type(f.x).__get__() wenn definiert, und f.x = y ruft f.x.__set__(y) auf, wenn definiert.

(Die oben genannten Anrufe __get__ und __set__ sind nur annähernd richtig, da ich die Details, welche Argumente __get__ links und __set__ tatsächlich erhalten, aber dies soll den Unterschied zwischen __get__ und __getattr[ibute]__. Genug sein, um zu erklären)

Setzen Sie noch einen anderen Weg, wenn MyDescriptor nicht definieren, dann f.x würde einfach die Instanz MyDescriptor zurückgeben.

+0

Oh .. Ich sehe jetzt. Danke, dass Sie diese Verbindungen klarer gemacht haben. Gibt es eine Möglichkeit, 'x = 3' zu machen (mit der Qualifizierung des Objekts ist die Methode verbunden?) – Inversus

+0

* (ohne Qualifizierung ... – Inversus

+0

Aber jetzt, wo ich ein bisschen damit gespielt habe. Ich denke __getattribute__ ist genau Was ich brauche Mein Anwendungsfall ist, wenn es sowieso in einer Sammlung ist, also denke ich, das wird funktionieren Danke, – Inversus

6

Für __getattr__ vs __getattribute__, siehe zum Beispiel Difference between __getattr__ vs __getattribute__.

ist nicht wirklich verwandt. Ich werde von den official documentation for the descriptor protocol hier zitieren:

Das Standardverhalten für Attribut Zugriff zu erhalten ist, eingestellt, oder das Attribut aus einem Wörterbuch des Objekts löschen. Zum Beispiel hat a.x eine Nachschlagekette, die mit a.__dict__['x'], dann type(a).__dict__['x'] beginnt und sich durch die Basisklassen von type(a) ohne Metaklassen fortsetzt. Wenn der nachgeschlagene Wert ein Objekt ist, das eine der Deskriptormethoden definiert, dann überschreibt Python möglicherweise das Standardverhalten und ruft stattdessen die Deskriptormethode auf. Wo dies in der Rangfolgekette auftritt, hängt davon ab, welche Deskriptormethoden definiert wurden.

Der Zweck __get__ zu steuern ist, was einmal a.x geschieht durch diesen „lookup chain“ gefunden wird (zum Beispiel ein Verfahren, Objekt zu erzeugen, anstatt eine einfache Funktion über type(a).__dict__['x'] gefunden zurückzukehren); Der Zweck von __getattr__ und __getattribute__ besteht darin, die Suchkette selbst zu ändern.

Es gibt keine __setattribute__, denn es gibt nur einen Weg zu tatsächlich gesetzt ein Attribut eines Objekts, unter der Haube. Vielleicht möchten Sie andere Dinge "magisch" passieren lassen, wenn ein Attribut gesetzt wird; aber __setattr__ deckt das ab. __setattribute__ könnte möglicherweise keine Funktionalität bieten, die __setattr__ nicht bereits.

Allerdings - die beste Antwort, in der überwältigenden Mehrheit der Fälle, ist nicht einmal daran zu denken, eines davon zu verwenden. Schauen Sie sich zuerst die Abstraktionen auf höherer Ebene an, z. B. property s, s und staticmethod s. Wenn Sie denken, dass Sie spezielle Werkzeuge wie diese benötigen und es nicht selbst herausfinden können, gibt es eine ziemlich gute Chance, dass Sie falsch in Ihrem Denken sind; Aber unabhängig davon ist es besser, in diesem Fall eine spezifischere Frage zu stellen.

Verwandte Themen