Seite 1 von 2

[gelöst] Python-Version auslesen

Verfasst: Mittwoch 7. Januar 2009, 16:58
von snafu
Hallo!

Mein Programm soll etwas anderes tun, wenn die Python-Version kleiner als 2.6 ist. Gibt es einen besseren Weg als das?

Code: Alles auswählen

import sys
version = float(sys.version[:3])
if version < 2.6:
    print 'kleiner'

Re: Python-Version auslesen

Verfasst: Mittwoch 7. Januar 2009, 17:11
von numerix
snafu hat geschrieben: Mein Programm soll etwas anderes tun, wenn die Python-Version kleiner als 2.6 ist. Gibt es einen besseren Weg als das?

Code: Alles auswählen

import sys
version = float(sys.version[:3])
if version < 2.6:
    print 'kleiner'
Ist doch in Ordnung so. Du kannst natürlich auch sys.version_info verwenden. Wenn du es ganz anders haben willst, hätte ich noch diese Lösung anzubieten: :lol:

Code: Alles auswählen

>>> try:
...     (1,).count(1)
... except AttributeError:
...     print "kleiner"
... 
kleiner

Verfasst: Mittwoch 7. Januar 2009, 17:11
von Redprince
Den Inhalt von sys.version_info hast du dir angesehen?

Verfasst: Mittwoch 7. Januar 2009, 17:18
von snafu
Jau, version_info finde ich persönlich sauberer.

Code: Alles auswählen

import sys
major, minor = sys.version_info[:2]
if major <= 2 and minor < 6:
    print 'kleiner'
Danke. :)

EDIT: Obwohl, nee. AND ist hier gar nicht gut...

Verfasst: Mittwoch 7. Januar 2009, 17:24
von BlackJack
Ich würde auf jeden Fall auch mal schauen, ob man das ohne die Versionsnummer machen kann. Hängt natürlich davon ab, was man machen möchte.

Edit: Wenn Du das ``and`` nicht magst:

Code: Alles auswählen

if sys.version_info[:2] < (2, 6):
    # ...

Verfasst: Mittwoch 7. Januar 2009, 17:47
von snafu
Das ist es. Danke BlackJack. :)

Es geht um mein "Modul-Lokalisierungs-Skript". Dort zeigt imp.find_module() unterschiedliche Verhaltensweisen, wenn man einen leeren String übergibt:

Code: Alles auswählen

Python 2.6 (r26:66714, Nov 16 2008, 20:39:17) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import imp
>>> imp.find_module('')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 
>>> 
Python 2.5.2 (r252:60911, Nov 14 2008, 19:46:32) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import imp
>>> imp.find_module('')
(None, '/usr/lib/python2.5/site-packages/PIL/', ('', '', 5))
Der Einheitlichkeit halber möchte ich an dieser Stelle Python < 2.6 das selbe Verhalten (ImportError werfen) beibringen wie der aktuellen Version.

http://paste.pocoo.org/show/98461/ (bisherige Version ohne die Anpassung)

EDIT: Obwohl, eigentlich ist das Unsinn. Die Meldung "No module named" ist ja ohnehin eher verwirrend. Ich werfe jetzt unabhängig von der Python-Version einen ImportError: "Module string is empty."

Verfasst: Mittwoch 7. Januar 2009, 19:25
von cofi
snafu hat geschrieben:EDIT: Obwohl, eigentlich ist das Unsinn. Die Meldung "No module named" ist ja ohnehin eher verwirrend. Ich werfe jetzt unabhängig von der Python-Version einen ImportError: "Module string is empty."
Macht es nicht mehr Sinn zu kontrollieren ob der String leer ist? ;)

Verfasst: Mittwoch 7. Januar 2009, 19:39
von numerix
snafu hat geschrieben:EDIT: Obwohl, eigentlich ist das Unsinn. Die Meldung "No module named" ist ja ohnehin eher verwirrend. Ich werfe jetzt unabhängig von der Python-Version einen ImportError: "Module string is empty."
Wieso ist die Meldung verwirrend? Ist doch eine klare Aussage: "Es wurde kein Modul benannt." Das trifft doch exakt den Punkt.

Verfasst: Mittwoch 7. Januar 2009, 19:43
von snafu
cofi hat geschrieben:Macht es nicht mehr Sinn zu kontrollieren ob der String leer ist? ;)
Mach ich ja auch jetzt:

Code: Alles auswählen

def get_path(module):
    "Return module's path. Return None if module is no file."
    if module == '':
        raise ImportError, 'Module string is empty.'
    f, path = imp.find_module(module)[:2]
    if f == None:
        return None
    try:
        return path
    finally:
        f.close()
@numerix: Die Meldung an sich ist nicht verwirrend. Sie sieht nur komisch aus, wenn dahinter kein Name steht, weil der übergebene String eben leer ist.

Verfasst: Mittwoch 7. Januar 2009, 19:45
von Birne94
sry, wenn ich was hier nicht peile (ka. ob ich aufm schlauch stehe), aber wieso wird da das return mit try abgefangen?
Um den Stream nach dem beenden der Funktion zu schließen? Denn ein Fehler kann da nicht so wirklich bei rauskommen, oder?

Verfasst: Mittwoch 7. Januar 2009, 19:46
von numerix
snafu hat geschrieben:@numerix: Die Meldung an sich ist nicht verwirrend. Sie sieht nur komisch aus, wenn dahinter kein Name steht, weil der übergebene String eben leer ist.
Ah, verstehe: Die Meldung ist eigentlich gar nicht so gemeint wie ich das übersetzt habe, sondern eigentlich steht da "Es gibt kein Modul mit dem Namen <Argument>" und dann fehlt der Name, weil kein Argument übergeben wurde. :idea: Dann ist es wirklich nicht schön.

Verfasst: Mittwoch 7. Januar 2009, 19:48
von snafu
Birne94 hat geschrieben:wieso wird da das return mit try abgefangen?
Um den Stream nach dem beenden der Funktion zu schließen? Denn ein Fehler kann da nicht so wirklich bei rauskommen, oder?
Da offene Streams auf jeden Fall geschlossen werden sollten, wollte ich auch den sehr unwahrschenlich, aber theoretisch dennoch möglichen Fall einbeziehen, dass die print-Zeile eine Exception wirft. Schaden kann es IMHO jedenfalls nicht.

EDIT: Obwohl, du hast Recht. Ich hatte das vorher anders strukturiert und da hatte es für mich mehr Sinn gemacht. Wenn aus irgendeinem Grund nicht auf Listenindex 1 (also das was ich an "path" binde) zugegriffen werden kann, würde er ja schon vorher meckern. Ich mach's raus...

(Ich frage mich gerade ohnehin, ob ein "finally" eigentlich greift, wenn im try-Block ein "return" steht)

Code: Alles auswählen

def get_path(module):
    "Return module's path. Return None if module is no file."
    if module == '':
        raise ImportError, 'Module string is empty.'
    f, path = imp.find_module(module)[:2]
    if f == None:
        return None
    f.close()
    return path

Verfasst: Mittwoch 7. Januar 2009, 20:03
von lunar
So unwahrscheinlich ist das gar nicht. Einen "broken pipe"-Fehler kann man recht leicht provozieren. Folgendes Skript namens "broken_pipe.py":

Code: Alles auswählen

import time

for i in xrange(5000):
    time.sleep(0.01)
    print 'hello world'
Die Ausgabe dieses Skripts an "head" pipen:

Code: Alles auswählen

$ python broken_pipe.py | head -n5
hello world
hello world
hello world
hello world
hello world
Traceback (most recent call last):
  File "/home/lunar/test/broken_pipe.py", line 5, in <module>
    print 'hello world'
IOError: [Errno 32] Broken pipe

Verfasst: Mittwoch 7. Januar 2009, 20:03
von Leonidas
Statt ``if f == None:`` besser ``if f is None`` denn ``None`` ist tatsächlich ein Singleton und man kann auf Objektidentität testen.

Verfasst: Mittwoch 7. Januar 2009, 20:36
von snafu
Leonidas hat geschrieben:Statt ``if f == None:`` besser ``if f is None`` denn ``None`` ist tatsächlich ein Singleton und man kann auf Objektidentität testen.
Okay, danke. War mir nicht bekannt.

@lunar: Selbst wenn ich jetzt mehrere Zeilen (z.B. für mehrere Module) ausgeben und diese Ausgabe tatsächlich durch ein Programm wie "head" begrenzen würde, dann wäre das Dateiobjekt aber in meinem Fall trotzdem geschlossen, bevor das print aus main() etwas in die Konsole schreibt, oder? Also jetzt bezogen auf die Variante ohne "finally".

Also kann ja eigentlich nur. Im Prinzip würde das nur Sinn machen, wenn ich das print-Statement direkt in die Funktion einbaue und ausführen lasse, bevor "f" geschlossen wird, was aber IMHO alles andere als guter Stil wäre...

Verfasst: Mittwoch 7. Januar 2009, 20:50
von lunar
snafu hat geschrieben:@lunar: Selbst wenn ich jetzt mehrere Zeilen (z.B. für mehrere Module) ausgeben und diese Ausgabe tatsächlich durch ein Programm wie "head" begrenzen würde, dann wäre das Dateiobjekt aber in meinem Fall trotzdem geschlossen, bevor das print aus main() etwas in die Konsole schreibt, oder? Also jetzt bezogen auf die Variante ohne "finally".
Vom "Datei-Objekt" kann man ja nicht mehr sprechen, da der Python-Interpreter zu diesem Zeitpunkt tot ist. Auf Betriebssystemebene werden die Ressourcen des Prozesses auf jeden Fall geschlossen, allerdings liegt zwischen dem Python-Interpreter und dem System noch die Standardbibliothek von C, die meist noch puffert. Dieser interne Puffer geht verloren, wenn sich das Programm nicht sauber beendet. Wenn man nur liest, ist das egal, weil der Puffer eh nur wiedergibt, was sich auf der Festplatte befindet.

Beim Schreiben allerdings gehen unter Umständen Daten verloren, deshalb sollte man Dateien, in die man schreibt, immer mit finally schließen oder innerhalb eines with-Statements verwenden. Nur so kann garantiert werden, dass die internen Puffer sauber gelehrt werden, sprich dass alle Daten, die man per "write" in die Datei schreibt, auch wirklich auf der Platte landen.

Verfasst: Mittwoch 7. Januar 2009, 21:08
von cofi
Leonidas hat geschrieben:Statt ``if f == None:`` besser ``if f is None`` denn ``None`` ist tatsächlich ein Singleton und man kann auf Objektidentität testen.
In dem Sinne kannst du auch `if module == '':' anpassen -> `if not module:'

Verfasst: Donnerstag 8. Januar 2009, 05:09
von str1442
try: return ... except / finally: funktioniert immer.

Verfasst: Donnerstag 8. Januar 2009, 13:37
von BlackJack
@cofi: Das geht nicht, weil vom ersten Fall dann auch `None` erfasst würde, das im gezeigten Quelltext aber anders behandelt werden soll als die leere Zeichenkette.

Verfasst: Donnerstag 8. Januar 2009, 13:58
von cofi
Wobei die Trennung von leeren Strings und None keinen großen Sinn ergibt bzw man bei None ebenfalls den ImportError (oder vielleicht besser einen ValueError?) raisen könnte.