Intercept-Operator-Suche in der Metaklasse

8

Ich habe eine Klasse, die mit jedem Operator etwas magisch machen muss, wie __add__ , __sub__ und so weiter.

Anstatt jede Funktion in der Klasse zu erstellen, habe ich eine Metaklasse, die jeden Operator im Operatormodul definiert.

%Vor%

Der Ansatz funktioniert gut, aber ich denke, es wäre besser, wenn ich den Ersatzoperator nur bei Bedarf erstelle.

Nachschlagen von Betreibern sollten auf dem Metaklasse, weil x + 1 in type(x).__add__(x,1) anstatt x.__add__(x,1) fertig ist, aber es nicht durch __getattr__ noch __getattribute__ Methoden nicht hängen bleiben.

Das geht nicht:

%Vor%

Außerdem muss die resultierende "Funktion" eine Methode sein, die an die verwendete Instanz gebunden ist.

Irgendwelche Ideen, wie ich diese Suche abfangen kann? Ich weiß nicht, ob es klar ist, was ich machen möchte.

Für diejenigen, die Fragen stellen, warum muss ich so etwas tun, überprüfen Sie den vollständigen Code hier . Das ist ein Werkzeug zum Erzeugen von Funktionen ( nur zum Spaß ), das als Ersatz für lambda s dienen könnte.

Beispiel:

%Vor%

Nur zur Erinnerung, ich möchte keinen anderen Weg kennen, um das Gleiche zu tun (ich werde nicht jeden einzelnen Operator in der Klasse erklären ... das wird langweilig sein und der Ansatz, mit dem ich recht gut zurecht gekommen bin: ). Ich möchte wissen, wie man die Attributsuche von einem Operator abfängt.

    
JBernardo 26.12.2011, 16:02
quelle

3 Antworten

5

Mit etwas schwarzer Magie erreichst du dein Ziel:

%Vor%

Ausgabe

%Vor%

Nun können Sie Ihr zweites Codebeispiel wörtlich verwenden, indem Sie von meiner OperatorHackiness -Basisklasse erben. Sie erhalten sogar einen zusätzlichen Vorteil: __getattr__ wird nur einmal pro Instanz und Operator aufgerufen, und es gibt keine zusätzliche Rekursionsebene für das Caching. Wir umgehen hiermit das Problem, dass Methodenaufrufe im Vergleich zur Methodensuche langsam sind (wie Paul Hankin richtig bemerkt hat).

HINWEIS : Die Schleife zum Hinzufügen der Operatormethoden wird nur einmal in Ihrem gesamten Programm ausgeführt, so dass die Vorbereitung einen konstanten Aufwand im Bereich von Millisekunden benötigt.

    
Niklas B. 29.12.2011, 16:22
quelle
3

Das Problem ist, dass Python die __xxx__ -Methoden für die Klasse des Objekts und nicht für das Objekt selbst sucht - und wenn es nicht gefunden wird, fällt es nicht auf __getattr__ oder __getattribute__ zurück.

Die einzige Möglichkeit, solche Aufrufe abzufangen, ist eine bereits vorhandene Methode. Es kann eine Stub-Funktion sein, wie in Niklas Baumstarks Antwort, oder es kann die vollwertige Ersatzfunktion sein; so oder so, dort muss etwas sein, das bereits dort ist, oder Sie werden nicht in der Lage sein, solche Anrufe abzufangen.

Wenn Sie genau lesen, werden Sie bemerkt haben, dass Ihre Anforderung, die finale Methode an die Instanz gebunden zu haben, keine mögliche Lösung ist - Sie können es tun, aber Python wird es niemals aufrufen, während Python die Klasse der Instanz, nicht die Instanz, für __xxx__ Methoden. Niklas Baumstarks Lösung, eine einzigartige temporäre Klasse für jede Instanz zu erstellen, ist so nah wie nur möglich.

    
Ethan Furman 02.01.2012 07:24
quelle
1

Es sieht so aus, als würden Sie die Dinge zu kompliziert machen. Sie können eine Mixinklasse definieren und von ihr erben. Dies ist einfacher als die Verwendung von Metaklassen und wird schneller ausgeführt als die Verwendung von __getattr__ .

%Vor%

Dann erbt jede Klasse, die diese Operatoren haben soll, von OperatorMixin.

%Vor%

Das Generieren der Operator-Methoden, wenn sie benötigt werden, ist keine gute Idee: __getattr__ ist langsam im Vergleich zur regulären Methoden-Suche, und da die Methoden einmal gespeichert sind (in der Mixin-Klasse), wird fast nichts gespeichert / p>     

user97370 26.12.2011 16:51
quelle