55 Stimmen

Django-Vorlage und der Trick mit den Locals

In den django-Büchern wird ein lokaler Trick beschrieben, um zu vermeiden, dass eine lange Liste von Parametern als Kontext-Wörterbuch eingegeben werden muss

http://www.djangobook.com/en/2.0/chapter04/

Ejemplo:

def current_datetime(request):
    dt_now = datetime.datetime.now()
    return render_to_response('current.html', {'dt_now': dt_now})

wird:

def current_datetime(request):
    dt_now = datetime.datetime.now()
    return render_to_response('current.html', locals())

Er empfiehlt dies für faule Programmierer, weist aber auf einen gewissen Overhead hin, der sich auf die Leistung auswirken kann.

Ich würde gerne wissen, ob einige von Ihnen den Trick mit den Einheimischen bei echten Anwendungen anwenden. Empfehlen Sie ihn oder ist er eine schlechte Praxis?

84voto

Alex Martelli Punkte 805329

Ich mag keine Wiederholungen - ich halte "DRY", "Don't Repeat Yourself", für ein wichtiges Programmierprinzip. Infolgedessen habe ich in der Tat verwendet locals() in ähnlichen Situationen. Das Rendern von Django-Vorlagen ist bei weitem nicht die einzige Situation dieser Art: Der allgemeine Fall ist "eine Funktion oder ein Operator, der ein Diktat akzeptiert, dem es aber nichts ausmacht, wenn das Diktat zusätzliche Einträge enthält". (Zum Beispiel ist die gewöhnliche String-Formatierung in Python ein weiterer solcher Fall).

Es gibt jedoch ein entgegengesetztes Prinzip: Programme sollten so lokalisiert wie möglich verständlich sein - das hilft bei der Wartung und der Umgestaltung (da es die Notwendigkeit erübrigt, andere Dateien zu untersuchen, um zu prüfen, welche Umgestaltungen akzeptabel sind). Dies legt nahe, für die locals() Fall, dass es in Ordnung ist, wenn die Vorlage (oder das String-Format usw.) ein lokales Literal ist (ein seltener Fall, in dem wahrscheinlich nur wenige Variablen verwendet werden und daher locals() ist kein großer Gewinn!-), aber problematisch für den Normalfall, dass die Vorlage in einer anderen Datei liegt.

Also, mit locals() in den meisten Fällen das Refactoring ernsthaft behindert. In fast jeder Situation in Python können lokale Variablen und ihre Namen als Teil eines lokalen Refactorings frei geändert werden, da sie keine "nach außen sichtbare" Wirkung haben... aber mit locals() bricht das - plötzlich kann man eine Variable nicht mehr sicher in einen anderen Namen umbenennen, der mehr Klarheit bietet, den Codefluss so umgestalten, dass eine Variable nicht mehr benötigt wird, usw., ohne jedes Mal eine separate Vorlagendatei zu studieren, um zu prüfen, ob der alte Name nicht mehr benötigt wird (und möglicherweise die Vorlagendatei zu bearbeiten, was nicht trivial sein kann, z. B. wenn sie für i18n/L10n-Zwecke in mehreren verschiedenen natürlichen Sprachen gepflegt wird).

Infolgedessen besteht neben der sekundären Frage der Leistung auch ein starker Druck gegen mit locals() in "ernsthaftem", "produktivem" Code - Code, der langfristig gewartet werden muss und daher leicht zu refaktorisieren und lokal zu halten ist. Wenn ich also "nach bestem Wissen und Gewissen programmiere", anstatt "an der falschen Stelle zu sparen", bin ich mir bewusst, dass ich besser vermeiden sollte locals() .

Die Werte, die Sie in dem Kontext haben wollen, in dem die Vorlage gerendert wird, sind ja nicht unbedingt "natürlich" als lokale Bare-Names verfügbar; vielleicht sind einige oder viele von ihnen Ergebnisse von Berechnungen, Elemente aus Listen oder Wörterbüchern und dergleichen. In diesem Fall ist die Versuchung groß, mit locals() ist leichter zu vermeiden, wenn Sie diese Werte einfach in einem geeigneten Wörterbuch sammeln, anstatt ihnen lokale bloße Namen zuzuweisen.

Es ist nicht der einfachste Kompromiss, da zwei gute Prinzipien (Vermeidung von Wiederholungen und gute Lokalisierung) unweigerlich miteinander kollidieren - daher eine gute Frage! Und keine, auf die es eine eindeutige schwarze oder weiße Antwort gibt, weshalb ich versucht habe, auf beide Seiten einzugehen. Letztendlich denke ich, dass es einer dieser "Stil"-Aspekte ist, bei dem ein Programmierteam gut beraten wäre, eine teameinheitliche Stilrichtlinie zu verabschieden und sich daran zu halten -- zumindest entfällt dadurch die Notwendigkeit, jedes Mal, wenn das Problem auftaucht, eine Entscheidung zu treffen, und es entsteht eine homogenere (und damit wartbare) Codebasis. [Ich muss gestehen, dass dieser spezielle Punkt in den Stilrichtlinien der Teams, in denen ich mitarbeite, nie explizit angesprochen wurde, obwohl viele andere dies getan haben!-)]

3 Stimmen

+1 aus mehreren Gründen. Einer, der mir sofort einfiel, wäre, wenn Sie eine Gruppe von Standard-Context_Prozessoren haben, die einige Standardwerte an alle Ihre Ansichten liefern. Es ist schon schlimm genug, wenn Sie versehentlich einen davon mit einem Wert überschreiben, der explizit an die Vorlage übergeben wurde, aber Sie werden sich die Haare raufen, wenn es ein zufälliges Überschreiben war, weil es einen local()-Wert mit dem gleichen Namen wie der "globale Name" vom Kontextprozessor gibt.

28voto

niels Punkte 595

Ich habe oft daran gedacht, Folgendes zu tun, bin mir aber nicht sicher, ob es wirklich hilfreich ist.

class MyStruct(object):
     pass

def my_view(request, id):
    c = MyStruct()
    c.customer = ..
    c.invoice = ..
    c.date = ..
    return render_to_response('xxx,html',c.__dict__)

8 Stimmen

Oh mein Gott! - Das ist genial!

1 Stimmen

Fügen Sie einfach diesen Kommentar zur Klassendefinition hinzu: # Die Attribute werden außerhalb der Klasse definiert. init pylint: disable=W0201

3 Stimmen

Warum nicht einfach ein einfaches Diktat verwenden?

14voto

Daniel Roseman Punkte 565786

Mir persönlich gefällt das nicht. Es gibt wahrscheinlich keinen Grund für meine Vorliebe, außer dem alten Python-Diktum "Explizit ist besser als implizit". Ich möchte genau wissen, was in meine Vorlagen eingeht.

0 Stimmen

Ich mag es auch nicht, es ist zu trocken und wenn ein Fehler auftritt, kann man ihn nicht gut beheben

3voto

Dave Webb Punkte 184809

Ich habe es (bisher!) ohne Probleme benutzt.

Ich mag das Tippen nicht besonders, deshalb mag ich es auch. Code wie

'customer' : customer,
'invoice' : invoice,
'date' : date

sieht für mich einfach lächerlich aus, und wenn ich es vermeiden kann, werde ich es tun. Einer der Gründe, warum ich Python mag, ist das Fehlen von Boilerplate (obwohl dies nicht wirklich Boilerplate ist, aber es ist ähnlich).

2voto

Tom van Enckevort Punkte 4170

Ich denke, es hängt davon ab, wie viele lokale Variablen Sie in Ihrer Funktion definieren.

Wenn sie genau mit der Zahl übereinstimmt, die Sie an Ihre Vorlage zurückgeben möchten, oder die "zusätzlichen" Variablen einfache Strukturen wie Ganzzahlen oder Boolesche Werte sind, dann hat es wohl keinen Sinn, sie explizit zurückzugeben, da dies mehr Arbeit erfordert.

Wenn Ihre Ansicht jedoch viele komplexe "Hilfsvariablen" enthält, wie z. B. Instanzen Ihres Modells, die Sie in der Ansicht verwenden, um die Daten zu generieren, die Sie an die Vorlage senden möchten, dann sollten Sie die Verwendung expliziter Variablen für die Rückgabe an die Vorlage in Betracht ziehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X