Seite 1 von 1

Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 11:55
von rhersel
Ich habe hier zwei seltsame Konstrukte die ich nicht richtig verstehe und auch keine Dokumentation dazu finde:

1.
result = [a for b in a if b == 1]
Was ist das: eine Listendefinition, eine for-Schleife, eine if-Condition???

2.
with open(cfg_file, 'wb') as configfile: cfg.write(configfile)
Ist 'with' ein Befehl? Wann braucht man das? Wo ist das dokumentiert?

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 12:12
von Dav1d
Zu 1.: Das ist eine LC (list comprehension)
Zu 2.: das ist das with-statement http://www.python.org/dev/peps/pep-0343/

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 12:21
von snafu
1) Das geht unter gewissen Umständen, auch wenn es - zumindest bei dem Beispiel, was mir einfällt - nicht allzuviel Sinn macht:

Code: Alles auswählen

>>> b = 1; a = (2,3)
>>> b == 1
True
>>> [a for b in a if b == 1]
[]
Nur hat man jetzt eben den letzten Wert der Iteration in `b` stehen:

Code: Alles auswählen

>>> b == 1
False
>>> b
3
>>> a
(2, 3)
...darauf kam ich jetzt auch nicht auf Anhieb. Ich möchte mal behaupten, das ist nichts, was man in der Art tun sollte.

2) http://docs.python.org/reference/compou ... .html#with + http://effbot.org/zone/python-with-statement.htm

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 12:36
von EyDu
@snafu: Auch wenn ich nicht verstehe, wie du in diesem Kontext auf das Thema kommt, aber die Dokumentation sagt folgendens:
http://docs.python.org/reference/expressions.html hat geschrieben:In Python 2.3 and later releases, a list comprehension “leaks” the control variables of each for it contains into the containing scope. However, this behavior is deprecated, and relying on it will not work in Python 3.0

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 12:55
von snafu
Ich komme auf das Thema durch das genannte Beispiel...

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 13:10
von rhersel
Danke für die Antworten. Ich glaube, jetzt hab ich's kapiert:
Die LC brauche ich z.B. um bei einer radio_button_group herauszufinden welcher radio_button gesetzt ist:

Code: Alles auswählen

radio_index = [radio_group.index(radio) for radio in radio_group if radio.get_active()][0]
Sehr praktisch.

Das WITH verstehe ich jetzt so:

Code: Alles auswählen

with machwas as ergebnis_von_machwas: machnochwas aber nur wenn machwas ok war
mach hier weiter auch wenn machwas fehlschlägt

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 13:27
von snafu
Nein, ein Context-Manager, mit dem das with-Statement benutzt werden kann, ist zwar meist so implementiert, dass er in der `__enter__`-Methode sich selbst zurück gibt - also das, was du `ergebnis_von_machwas` nennst -, aber in der `__exit__`-Methode, d.h. dem Moment, in dem der Kontext verlassen wird, sollen Dinge stehen, die *in jedem Fall* ausgeführt werden. Das bedeutet, eine Ausnahme kann geworfen werden und das Programm abbrechen, aber es wird in jedem Fall vorher z.B. die Datei geschlossen. Das bedeutet aber auch, dass der Code nach dem "with-Block" nur dann weiter ausgeführt wird, wenn eben kein Fehler geworfen wurde.

Durch dein konkretes Beispiel zu 1) verstehe ich jetzt auch, was du meintest. Da hab ich wohl nicht weit genug um die Ecke gedacht. Evtl meintest du auch schon meine o.g. Ausführungen mit deinem komischen Beispiel, aber dann sprechen wir wirklich recht unterschiedliche Sprachen. ;)

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 13:38
von cofi
`with` ist ein `try ... finally` auf Steroiden und mit eigener Intelligenz.
Leider kann man das in Code nur per Macros erklaeren, aber ich bezweifel, dass Lisp dir hilft.

Naja vllt mal mit Pseudocode:

Code: Alles auswählen

with expression as foo:
    suite
Wird zu

Code: Alles auswählen

try:
    foo = expression().__enter__()
    suite
finally:
    foo.__exit__()

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 14:01
von EyDu
Mal abgesehen von dem "expression()", welches nur "expression" heißen müsste, muss die ganze Zeile vor das try geschoben werden. Sonst könnte es beispielsweise passieren, dass eine noch nicht geöffnete Datei geschlossen werden soll. Die genaue Übersetzung findtet sich übrigens in PEP 343.

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 14:07
von DasIch
snafu hat geschrieben:[...]aber in der `__exit__`-Methode, d.h. dem Moment, in dem der Kontext verlassen wird, sollen Dinge stehen, die *in jedem Fall* ausgeführt werden.
Nicht wirklich. __exit__ bekommt den Typ und Wert der Ausnahme sowie den Traceback als Argumente übergeben und man kann dementsprechend auf Ausnahmen reagieren.

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 14:33
von b.esser-wisser
@cofi: Dein with-ersatz ist nicht ganz richtig:

Code: Alles auswählen

In [1]: class Spam(object):
   ...:     def __enter__(self):
   ...:         raise Exception("Foo!")
   ...:     def __exit__(self):
   ...:         print "running __exit__()"

In [2]: with Spam():
   ...:     pass
   ...:
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)

C:\Dokumente und Einstellungen\...\Desktop\<ipython console> in <module>()

C:\Dokumente und Einstellungen\...\Desktop\<ipython console> in __enter__(self)

Exception: Spam!
Soll heißen, __exit__() wird nicht ausgeführt, wenn in __enter__() eine Ausnahme auftritt - dann ist ja auch der return-Wert von __enter__ nicht vorhanden.

hth, Jörg

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 14:39
von snafu
DasIch hat geschrieben:
snafu hat geschrieben:[...]aber in der `__exit__`-Methode, d.h. dem Moment, in dem der Kontext verlassen wird, sollen Dinge stehen, die *in jedem Fall* ausgeführt werden.
Nicht wirklich. __exit__ bekommt den Typ und Wert der Ausnahme sowie den Traceback als Argumente übergeben und man kann dementsprechend auf Ausnahmen reagieren.
Die Prüfung der Ausnahme ist auch etwas, das in jedem Fall ausgeführt wird. Ich kann's aber auch anders ausdrücken: `__exit__` wird in jedem Fall bei Verlassen des Kontexts aufgerufen. Dies kann passiert sein durch eine Ausnahme oder durch Erreichen des Blockendes. Dementsprechend wird in diesem Moment der Code ausgeführt, der in der `__exit__`-Methode drinsteht.

Re: Zwei komische Python Konstrukte

Verfasst: Freitag 28. Mai 2010, 16:02
von BlackJack
@rhersel: Also ich finde Dein Anwendungsbeispiel für die "list comprehension" nicht so schön. Das sieht aus als wenn die nur verwendet wird um Zeilen zu sparen. Auf Kosten der Verständlichkeit. Man muss nämlich erst ans Ende des Ausdrucks schauen um zu sehen, dass es hier gar nicht darum geht eine Liste zu erzeugen, sondern ein *einzelnes* Element aus einer anderen Liste auszusuchen. Ausserdem geht die `index()`-Methode die Liste wieder linear von vorne durch um das Element zu suchen, das ja eigentlich gerade gefunden wurde. Wenn man gleich die Indizes mitzählt, kommt man mit einem Durchlauf der Liste aus:

Code: Alles auswählen

radio_index = [i for (i, b) in enumerate(radio_group) if b.get_active()][0]