Hallo Gruppe, In einer List comprehension funktioniert ja folgendes: mynewlist = [ foo(item) for item in myoldlist if bar(item) ] Wenn man die Schleife aufdröseln will, geht das leider nicht so einfach: mynewlist = [] for item in myoldlist: if bar(item): mynewlist.append(foo(item)) Warum geht hier nicht folgendes? for item in myoldlist if bar(item): mynewlist.append(foo(item)) (Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?) Cheers Ole
Weil Schleifen in Python schon immer und ewig so aussahen....warum sollte man sie ändern wollen? Syntaktischer Zucker... -aj Am 9. Mai 2012 14:23 schrieb Olе Streicher <ole-usenet-spam@gmx.net>:
Hallo Gruppe,
In einer List comprehension funktioniert ja folgendes:
mynewlist = [ foo(item) for item in myoldlist if bar(item) ]
Wenn man die Schleife aufdröseln will, geht das leider nicht so einfach:
mynewlist = [] for item in myoldlist: if bar(item): mynewlist.append(foo(item))
Warum geht hier nicht folgendes?
for item in myoldlist if bar(item): mynewlist.append(foo(item))
(Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?)
Cheers
Ole _______________________________________________ python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de
Am 09.05.2012 14:23 schrieb Olе Streicher:
Hallo Gruppe,
In einer List comprehension funktioniert ja folgendes:
mynewlist = [ foo(item) for item in myoldlist if bar(item) ]
In einer Generator expression auch...
Wenn man die Schleife aufdröseln will, geht das leider nicht so einfach:
mynewlist = [] for item in myoldlist: if bar(item): mynewlist.append(foo(item))
Warum geht hier nicht folgendes?
for item in myoldlist if bar(item): mynewlist.append(foo(item))
Schwer zu sagen. Mir hat es auch schon gefehlt. Aber - auch wen die beiden gleich aussehen -: ich nehme an, daß die verschiedenen for-Inkarnationen grammatikalisch nicht viel miteinander zu tun haben. Auf der einen Seite gibt es for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite] , desweiteren für List Comprehensions list_display ::= "[" [expression_list | list_comprehension] "]" list_comprehension ::= expression list_for list_for ::= "for" target_list "in" old_expression_list [list_iter] old_expression_list ::= old_expression [("," old_expression)+ [","]] old_expression ::= or_test | old_lambda_form list_iter ::= list_for | list_if list_if ::= "if" old_expression [list_iter] comprehension ::= expression comp_for comp_for ::= "for" target_list "in" or_test [comp_iter] comp_iter ::= comp_for | comp_if comp_if ::= "if" expression_nocond [comp_iter] Und vermutlich ist es im Parser/Lexer (wer auch immer dafür zuständig ist, kenne mich da nicht so aus...) daher auch an unterschiedlichen Stellen implementiert. Schöner wäre sicherlich einfach ein for_stmt ::= "for" target_list "in" expression_list [list_iter or comp_iter]":" suite ["else" ":" suite] - das würde auch verschachtelte Shleifen vereinfachen. Ansonsten muß man sich eben mit for item in (item for item in myoldlist if bar(item)): ... behelfen. BTW: In Deinem Fall ginge auch ein Einzeiler: mynewlist.extend(foo(item) for for item in myoldlist if bar(item)) HTH, Thomas
Thomas Rachel writes:
Am 09.05.2012 14:23 schrieb Olе Streicher:
In einer List comprehension funktioniert ja folgendes: mynewlist = [ foo(item) for item in myoldlist if bar(item) ] In einer Generator expression auch...
Yep.
Wenn man die Schleife aufdröseln will, geht das leider nicht so einfach: Warum geht hier nicht folgendes? for item in myoldlist if bar(item): mynewlist.append(foo(item))
Schwer zu sagen. Mir hat es auch schon gefehlt. Aber - auch wen die beiden gleich aussehen -: ich nehme an, daß die verschiedenen for-Inkarnationen grammatikalisch nicht viel miteinander zu tun haben.
Es wäre aber doch sicherlich schlauer, wenn "for" sich immer ähnlich verhält, oder? Man hat ja nicht umsonst das gleiche Keyword genommen.
Schöner wäre sicherlich einfach ein
for_stmt ::= "for" target_list "in" expression_list [list_iter or comp_iter]":" suite ["else" ":" suite]
- das würde auch verschachtelte Shleifen vereinfachen.
Ja; dort fehlt IMO auch ein for i in range(4) for j in range(5): print('%s * %s = %2s' % (i, j, i*j))
Ansonsten muß man sich eben mit for item in (item for item in myoldlist if bar(item)): behelfen.
... was nicht gerade übersichtlich aussieht :-(
BTW: In Deinem Fall ginge auch ein Einzeiler:
mynewlist.extend(foo(item) for for item in myoldlist if bar(item))
Das ist schon klar. Mein Problem ist aber Minidom: for c in f.childNodes if c.localName == 'header': for p in c.childNodes if p.localName == 'property': print('%s = %s' % (p.getAttribute('name'), p.getAttribute('value'))) was in dieser Form leichtverständlich ist, aber ohne den syntaktischen Zucker eben deutlich schwerer nachvollziehbar. Viele Grüße Ole
Am 9. Mai 2012 15:15 schrieb Olе Streicher <ole-usenet-spam@gmx.net>:
Das ist schon klar. Mein Problem ist aber Minidom:
for c in f.childNodes if c.localName == 'header': for p in c.childNodes if p.localName == 'property': print('%s = %s' % (p.getAttribute('name'), p.getAttribute('value')))
was in dieser Form leichtverständlich ist, aber ohne den syntaktischen Zucker eben deutlich schwerer nachvollziehbar.
Das ist doch eine unnötige Phantomschmerz-Diskussion. Schreib Dir eine Method, die die Filterung übernimmt und Implementationsdetails verbringt *oder* nimm gleich einen ordentlichen Parser und verwende XPath. -aj
Das ist schon klar. Mein Problem ist aber Minidom:
for c in f.childNodes if c.localName == 'header': for p in c.childNodes if p.localName == 'property': print('%s = %s' % (p.getAttribute('name'), p.getAttribute('value')))
was in dieser Form leichtverständlich ist, aber ohne den syntaktischen Zucker eben deutlich schwerer nachvollziehbar.
Hm. Vielleicht ja def filterlocalname(node, name): for child in node.childNodes: if child.localName == name: yield child oder einfach filterlocalname = lambda node, name: ( child for child in node.childNodes if child.localName == name ) und dann: for c in filterlocalname(f, 'header'): for p in filterlocalname(c, 'property'): print('%s = %s' % (p.getAttribute('name'), p.getAttribute('value'))) Hab grade überlegt, ob sich nicht einfacher was mit getElementsbyTagName() oder so machen ließe, aber das berücksichtigt nicht die Beschränkung auf "header" auf der 1. Ebene... Thomas
* Olе Streicher wrote:
Das ist schon klar. Mein Problem ist aber Minidom:
for c in f.childNodes if c.localName == 'header': for p in c.childNodes if p.localName == 'property': print('%s = %s' % (p.getAttribute('name'), p.getAttribute('value')))
was in dieser Form leichtverständlich ist, aber ohne den syntaktischen Zucker eben deutlich schwerer nachvollziehbar.
ich baue mir bei sowas gerne lokale Mini-Funktionen, die die Semantik besser abbilden. Durch die Lokalität bleibt auch das Gesamtbild erhalten und der globale Namensraum wird nicht gestört. def children(node, which): # Einzeiler: return (child for child in node.childNodes if child.localName == which) # ODER # ich neige allerdings zu for-schleifen mir yield. # vertikal ist netter: for child in node.childNodes: if child.localName == which: yield child for header in children(f, 'header'): for prop in children(header, 'property'): # dosomething nd -- die (eval q-qq[Just Another Perl Hacker ] ;-) # André Malo, <http://www.perlig.de/> #
Am 09.05.2012 14:23, schrieb Olе Streicher:
for item in myoldlist if bar(item): mynewlist.append(foo(item))
(Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?) Weil's unverständlich ist?!
Bezieht sich das `if` auf die For-Schleife, oder auf `myoldlist`? Unnötig kompliziert, nur um ein paar Zeichen zu sparen. -- Schönen Gruß - Regards Hartmut Goebel Dipl.-Informatiker (univ.), CISSP, CSSLP Goebel Consult Spezialist für IT-Sicherheit in komplexen Umgebungen http://www.goebel-consult.de Monatliche Kolumne: http://www.cissp-gefluester.de/ Goebel Consult ist Mitglied bei http://www.7-it.de
Hartmut Goebel, 09.05.2012 16:21:
Am 09.05.2012 14:23, schrieb Olе Streicher:
for item in myoldlist if bar(item): mynewlist.append(foo(item))
(Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?) Weil's unverständlich ist?!
Bezieht sich das `if` auf die For-Schleife, oder auf `myoldlist`? Unnötig kompliziert, nur um ein paar Zeichen zu sparen.
Ja, das ist auch das Hauptargument, wenn dieser Vorschlag mit einiger Regelmäßigkeit auf den Python-Mailinglisten auftaucht. Stefan
Am 11.05.2012 11:37 schrieb Stefan Behnel:
Hartmut Goebel, 09.05.2012 16:21:
Am 09.05.2012 14:23, schrieb Olе Streicher:
for item in myoldlist if bar(item): mynewlist.append(foo(item))
(Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?) Weil's unverständlich ist?!
Bezieht sich das `if` auf die For-Schleife, oder auf `myoldlist`? Unnötig kompliziert, nur um ein paar Zeichen zu sparen.
Ja, das ist auch das Hauptargument, wenn dieser Vorschlag mit einiger Regelmäßigkeit auf den Python-Mailinglisten auftaucht.
Kann ich nicht nachvollziehen. Ich nehme an, daß das Ganze auf a if b else c abzielt. Aber 1. fehlt da ja dann der else-Teil und 2. wäre das bei List comprehensions, Generator expressions und dem seit 2.7 bei set und dict vorkommenden Teilen ebenso: i for i in a if b vs. i for i in a if b else c Grade getestet: Letzteres läßt sich in [] und () nicht parsen, aber dennoch sollte es doch auch einen Weg geben, for i in a if b else c: i von dem (noch) nicht exisitierenden for i in a if b: i zu unterscheiden... Thomas
Am 11. Mai 2012 12:38 schrieb Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de>:
Am 11.05.2012 11:37 schrieb Stefan Behnel:
Hartmut Goebel, 09.05.2012 16:21:
Am 09.05.2012 14:23, schrieb Olе Streicher:
for item in myoldlist if bar(item): mynewlist.append(foo(item))
(Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?)
Weil's unverständlich ist?!
Bezieht sich das `if` auf die For-Schleife, oder auf `myoldlist`? Unnötig kompliziert, nur um ein paar Zeichen zu sparen.
Ja, das ist auch das Hauptargument, wenn dieser Vorschlag mit einiger Regelmäßigkeit auf den Python-Mailinglisten auftaucht.
Kann ich nicht nachvollziehen. Ich nehme an, daß das Ganze auf a if b else c abzielt.
In Comprehensions und Generatorausdrücken kann man auf ein eigenes "if" nicht verzichten. Beides sind grammatikalisch Ausdrücke (aka expressions). Ausdrücke können keine Anweisungen (aka "statements") enthalten. Mithin kann man in solchen Ausdrücken kein „normales“ "if" nutzen, um bestimmte Elemente zu überspringen. Eine eigene grammatikalische Regel für Bedingungen in Comprehensions und Generatorausdrücken ist mithin unabdingbar. Eine "for"-Anweisung allerdings erwartet als nächstes Token einen Block, in welchem wiederum weitere Anweisungen stehen können. Mithin kann man an dieser Stelle eine normale "if"-Anweisung nutzen, um Elemente zu überspringen. Es bedarf keiner weiteren zusätzlichen Regel, welche die Grammatik verkomplizieren würde und das Prinzip des Zen, dass es einen offensichtlichen Weg geben soll, verletzen würde. Es spricht ja im Übrigen auch nichts dagegen, "for"-Schleifen mit Generatorausdrücken zu kombinieren, i.e. headers = (n for n in node.childNodes if n.localName == 'header') for node in header: # … Ich persönlich finde das ohnehin eleganter, da man so reine Datenverarbeitung ohne Seiteneffekte von potentiell seiteneffektbehafteten Anweisungen trennt, also einen „funktionaleren“ Programmierstil verwendet. Generell würde ich "for"-Schleifen falls möglich nur für Seiteneffekte wie beispielsweise die Ausgabe von Daten nutzen, und ansonsten eher Iteratoren, Generatoren und Funktionen, allgemein implizite Iteration, nutzen, um Daten zu verarbeiten und zu filtern.
Hallo,
(Schon klar: weil es die Syntax nicht zulässt. Aber warum wurde das so designed?)
Ich denke, das hängt damit zusammen, das die beiden Konstrukte eine ganz unterschiedliche Historie haben. Die for-Schleife ist aus der imperativen Welt. Die List-Comprehension kommt auf der funktionalen Welt. Sie lehnt sich an die Mengentheorieschreibweise an. s = { 2*x | x e N , x^2 > 3 } (e steht für das matematische Element Symbol) oder in Python s = [ 2*x for x in N if (x*x) > 3 ] Tatsächlich ist die List-Comprehension nur Syntactic Sugar für die zwei funktionalen Funktionen map und filter. Genauer lässt sich dies auf Wikipedia nachlesen. Gruß, Rainer
participants (8)
-
Andreas Jung
-
André Malo
-
Hartmut Goebel
-
ole-usenet-spam@gmx.net
-
r.grimm@science-computing.de
-
Sebastian Wiesner
-
Stefan Behnel
-
Thomas Rachel