Zwei komische Python Konstrukte

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
rhersel
User
Beiträge: 105
Registriert: Mittwoch 3. Dezember 2008, 11:29

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?
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Zu 1.: Das ist eine LC (list comprehension)
Zu 2.: das ist das with-statement http://www.python.org/dev/peps/pep-0343/
the more they change the more they stay the same
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@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
Das Leben ist wie ein Tennisball.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich komme auf das Thema durch das genannte Beispiel...
rhersel
User
Beiträge: 105
Registriert: Mittwoch 3. Dezember 2008, 11:29

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
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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. ;)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

`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__()
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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.
Das Leben ist wie ein Tennisball.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

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.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

@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
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
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]
Antworten