2010-03-12 16 views
6

Ich habe eine Klasse, die eine output() -Methode hat, die eine Matplotlib-Figur -Instanz zurückgibt. Ich habe einen Dekorateur, den ich geschrieben habe und der diese Feigeninstanz zu einem Django-Antwortobjekt macht.Übergabe von Schlüsselwortargumenten an einen Klassenmethode-Decorator

Mein Dekorateur sieht wie folgt aus:

class plot_svg(object): 
    def __init__(self, view): 
     self.view = view 

    def __call__(self, *args, **kwargs): 
     print args, kwargs 
     fig = self.view(*args, **kwargs) 
     canvas=FigureCanvas(fig) 
     response=HttpResponse(content_type='image/svg+xml') 
     canvas.print_svg(response) 
     return response 

und das ist, wie es verwendet wurde:

def as_avg(self): 
    return plot_svg(self.output)() 

Der einzige Grund, warum ich es auf diese Weise statt mit dem „@“ Syntax ist denn wenn ich es mit dem "@" zu tun:

@plot_svg 
def as_svg(self): 
    return self.output() 

ich diesen Fehler:

Ich versuche, dies zu beheben, indem ich es in die "@" - Syntax setze, aber ich kann nicht herausfinden, wie es funktioniert. Ich denke, es hat etwas zu tun mit self nicht bekommen, wo es soll ...

Antwort

6

Richtig: wenn Sie mit einer Klasse dekorieren, anstatt mit einer Funktion, müssen Sie es zu einem Deskriptor (geben Sie es eine Methode, mindestens), um das "automatische Selbst" zu erhalten. Einfachste ist mit einer Funktion zu dekorieren statt:

def plot_svg(view): 

    def wrapper(*args, **kwargs): 
     print args, kwargs 
     fig = view(*args, **kwargs) 
     canvas = FigureCanvas(fig) 
     response = HttpResponse(content_type='image/svg+xml') 
     canvas.print_svg(response) 
     return response 

    return wrapper 

Hintergrund: Die Grund-Funktionen „werden Methoden“ (wenn in einer Klasse definiert und auf einer Instanz davon durch zugegriffen Attribut-get-Notation), mit anderen Worten, der Grund, solche Funktionen können ihre automatische self bekommen, dass sie Deskriptoren sind - der Funktionstyp hat eine .

Eine Klasse verfügt nicht über eine -Methode - es sei denn, Sie fügen explizit eine hinzu. Warum also nicht einfach mit einer Funktion dekorieren, wie im obigen Beispiel? Auf diese Weise erhalten Sie automatisch die netten von Funktionen - und wie Sie sehen, die geschachtelte Funktion "lexikalische Schließung" Eigenschaft stellt überhaupt kein Problem (in der Tat, es vereinfacht Dinge - die geschachtelte Funktion ruft view, nicht , die möglicherweise eher verwirrend, wenn self entweder eine Instanz Ihrer Dekoratorklasse ODER eine Instanz der Klasse bedeuten könnte, deren Methode Sie schmücken ...! -).

+0

Ich bin durch Ihre Antwort verwirrt. Ich hatte gedacht, dass die Substitution der erwarteten lexikalischen Substitution entspricht. Also: @plot_svg (view = eine_sicht) def some_func (some_args): ... -> (minus Zwischenvariablen/Bindungen) def some_func (some_args): ... a_plot_instance = plot_svg .__ init __ (view = some_view) some_func = a_plot_instance .__ Aufruf __ (some_args) Können Sie das klären? Und ich hasse fehlende Formatierung von Kommentaren. –

+0

@ charles.merriam: da ** ist ** Kommentar Formatierung. Verwenden Sie \ * \ * für ** Fett **, \ * für * Kursivschrift *, Backticks (\ ') für' Code', etc ... Sie müssen jetzt möglicherweise einen umgekehrten Schrägstrich verwenden ... – ChristopheD

+0

Ich bin verwirrt durch deine Antwort. Ich hatte gedacht, dass die Substitution der erwarteten lexikalischen Substitution entspricht. Also: '@plot_svg (view = some_view)' \ n 'def einige_func (some_args): ...' \ n -> (minus Zwischenvariablen/Bindungen) \ n 'def some_func (some_args): ... '\ n ' a_plot_instance = plot_svg .__ init __ (Ansicht = Some_view) '\ n ' some_func = a_plot_instance .__ Aufruf __ (some_args) '\ n Kannst du das klären? –

1

OK, es scheint ein paar Probleme zu geben.

Zuerst einige Syntax. Sie erhalten den Fehler "Take exactly one argument", weil Ihr Decorator @ plot_svg einen Parameter (eine Ansicht) erwartet. Es gibt auch andere Syntaxfehler.

Zweitens, und noch wichtiger, Sie möchten eine Funktion anstelle eines Dekorators schreiben. Ein Dekorateur zerstört Ihren Zugang zu einem Konzept und gibt Ihnen nur Zugriff auf das kombinierte Konzept. Sie wollen einfach nur eine neue Funktion wie folgt aus:

def as_svg(an_object): 
    return django_response(an_object.output()) 

Alternativ ich falsch verstehen Ihre Frage ein wenig zu wenig Code Beispiel.

Verwandte Themen