Ich habe eine andere Frage zu Stack Overflow ( Zen von Python ) gelesen und bin auf dieses Problem gestoßen Linie in Jaime Sorianos Antwort:
%Vor%Wenn Sie oben in einer Python-Shell eingeben, wird Folgendes ausgegeben:
%Vor%Und natürlich war ich gezwungen, den ganzen Vormittag damit zu verbringen, die obige Liste ... Verständnis ... zu verstehen. Ich zögere, es flach zu erklären, aber nur, weil ich nur anderthalb Monate programmiert habe, und bin daher unsicher, ob solche Konstruktionen in Python üblich sind oder nicht.
this.s
enthält eine codierte Version des obigen Ausdrucks:
Und this.d
enthält ein Wörterbuch mit der Chiffre, die this.s
dekodiert:
Soweit ich das beurteilen kann, ist der Ablauf der Ausführung in Jaimes Code wie folgt:
1. Die Schleife c for c in this.s
weist c
einen Wert zu
2. Wenn die Anweisung c in this.d
True ergibt, führt die "and" -Anweisung aus, was auch immer passiert, in diesem Fall this.d[c]
3. Wenn die Anweisung c in this.d
zu False führt (was im Code von Jaime nie passiert), führt die "oder" -Anweisung das aus, was gerade passiert, in diesem Fall die Schleife c for c in this.s
.
Habe ich diesen Fluss richtig?
Auch wenn ich bezüglich der Reihenfolge der Ausführung recht habe, hinterlässt das immer noch eine Menge Fragen. Warum ist & lt; 1 & gt; das erste, was ausgeführt wird, obwohl der Code dafür nach mehreren bedingten Anweisungen zuletzt auf der Zeile steht? Mit anderen Worten: Warum beginnt die for
-Schleife mit der Ausführung und dem Zuweisen von Wert, gibt aber nur tatsächlich einen Wert zu einem späteren Zeitpunkt der Codeausführung zurück, wenn überhaupt?
Auch für Bonuspunkte, was ist mit der seltsamen Linie in der Zen-Datei über die Holländer?
Edit: Obwohl es mich beschämt, es jetzt zu sagen, nahm ich bis vor drei Sekunden an, dass Guido van Rossum Italiener war. Nachdem ich seinen Wikipedia-Artikel gelesen habe, verstehe ich zumindest, wenn nicht vollständig, warum diese Zeile dort ist.
Sie haben den Fluss richtig.
Die Schleife ist von der Art [dosomething(c) for c in this.s]
Es ist ein Listenverständnis und sollte als dosomething für alle c in diesem s gelesen werden.
Der niederländische Teil handelt von Guido Van Rossum, der Schöpfer von Python ist Niederländisch.
Ihre Analyse ist nahe. Es ist ein Listenverständnis. (Übrigens würde dieselbe Ausgabe resultieren, wenn die äußeren eckigen Klammern eliminiert würden, was als Generatorverständnis bezeichnet würde)
Es gibt eine Dokumentation hier .
Die Grundform eines Listenverständnisses ist
%Vor%Sie werden in dieser Reihenfolge ausgewertet:
Das Ergebnis ist die Liste der Ausdruckswerte für jedes Element im Aufzählungselement, für das die Bedingung zutrifft.
In diesem Beispiel wird keine Bedingung verwendet. Nach dem Hinzufügen einiger Klammern bleibt also Folgendes übrig:
%Vor% this.s
ist das Aufzählbare. c
ist die Iterationsvariable. c in this.d and this.d[c] or c
ist der Ausdruck.
c in this.d and this.d[c] or c
verwendet die Kurzschluß-Natur der logischen Operatoren von Python, um dasselbe wie this.d[c] if c in this.d else c
zu erreichen.
Alles in allem würde ich das nicht verschleiert nennen. Sobald Sie die Macht der Liste Verständnis verstehen, wird es ganz natürlich aussehen.
Im Allgemeinen haben Listenergänzungen die folgende Form:
%Vor%Wenn ich ein Listenverständnis schreibe, beginne ich oft damit,
zu schreiben %Vor%weil viele Jahre der prozeduralen Programmierung den for-loop Aspekt in meinen Verstand als den Teil eingeprägt haben, der zuerst kommt.
Und wie Sie richtig bemerkt haben, ist die for-Schleife der Teil, der zuerst "auszuführen" scheint.
Bei jedem Durchgang durch die Schleife wird der Ausdruck ausgewertet. (Ein kleiner Punkt: Ausdrücke werden ausgewertet, Anweisungen werden ausgeführt.)
Also in diesem Fall haben wir
%Vor%this.s ist eine Zeichenfolge. In Python sind Strings Iteratoren! Wenn Sie
schreiben %Vor% Die Schleife iteriert über die Zeichen in der Zeichenfolge. So nimmt c
jedes der Zeichen in dieser Reihenfolge in der Reihenfolge an.
Jetzt ist der Ausdruck
%Vor%Dies ist eine ternäre Operation . Dieser Link erklärt die Logik, aber die Grundidee ist
%Vor% Die Bedingung c in this.d
ist also einfach zu überprüfen, dass das dict this.d
einen Schlüssel mit dem Wert c
hat. Wenn dies der Fall ist, geben Sie this.d[c]
zurück, und wenn nicht, geben Sie c
selbst zurück.
Eine andere Möglichkeit, es zu schreiben wäre
%Vor%(das zweite Argument der Methode get ist der Standardwert, der beim ersten Argument zurückgegeben wird ist nicht im dict).
PS. Die ternäre Form
%Vor% ist fehleranfällig. (Überlegen Sie, was passiert, wenn condition
True ist, aber value1
ist None
. Da condition
True ist, können Sie erwarten, dass das ternäre Formular auf value1
, also None
, auswertet. co_de% hat den booleschen Wert None
, die ternäre Form wird stattdessen als False
ausgewertet, und wenn Sie sich dieser Gefahr nicht bewusst sind, kann das ternäre Formular Fehler verursachen.)
Für moderne Python-Versionen wäre es besser, dies zu schreiben:
%Vor% Es ist nicht anfällig für die oben genannten Fallstricke. Wenn value2
True ist, wird der Ausdruck immer als condition
ausgewertet.
Aber im obigen speziellen Fall würde ich value1
bevorzugen.
"".join([c in this.d and this.d[c] or c for c in this.s])
ist sicherlich verschleiert. Hier ist eine Zen-Version:
this.s.decode('rot13')
Meine Version mit modernem if else und Generator:
%Vor%Verbale Version: importieren Sie dies, das Hauptprogramm entschlüsselt und druckt die Nachricht this.s Um die Nachricht zu entschlüsseln, ersetzen Sie die Buchstaben, die in dict this.d mit ihren dekodierten Zählerteilen gefunden werden (Groß- / Kleinschreibung unterschiedlich). Die anderen Buchstaben müssen sich nicht ändern, sondern so drucken, wie sie sind.
Tags und Links python obfuscation execution control-flow