Sesam öffne dich

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
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Leute,

ich bin beim Öffnen einer normalen Text-Datei etwas verwirrt. Hier zunächst mein Code.

Code: Alles auswählen

    def read_licence(self):
        licence_file = None
        setting_folder = unicode(os.path.abspath(os.path.join('licences', 'Licence GPL2.txt')), "UTF-8")
        try:
            licence_file = open(setting_folder).read()
            self.ui_pp_about.textEditLicence.setText(licence_file)
            print("\n\nRead licence-file from: " + setting_folder)
        except (IOError, ValueError):
            QMessageBox.information(None, 'ERROR', licence_file.errorString())
            print "An I/O error or a ValueError occurred"
        except:
            print "An unexpected error occurred"
            raise
        finally:
            if licence_file is not None:
               licence_file.close()
Wie wir sehen, möchte ich eine Text-Datei öffnen, und diesen Inhalt auf das QWidget namens textEditLicence "übertragen". Eine Frage vorweg: Wie ihr im finally-Block seht, versuche ich die Datei immer zu schließen. Jedoch wirft Python die Fehlermeldung:
File "D:\Dan\Python\project_xarphus\files\modules_ui\ui_pp_about.py", line 115, in read_licence
licence_file.close()
AttributeError: 'str' object has no attribute 'close'
Schließt Python denn nach dem Lesen (read()) die Datei selbst, oder muss ich mich als Programmierer selbst darum kümmern?
BlackJack

@Sophus: `licence_file` müsstest Du schon an eine *Datei* binden (Typ `file`) und nicht an den Inhalt (Typ `str`). Der übliche Weg ist aber sowieso die ``with``-Anweisung dafür zu verwenden.

Wenn man es schon mit `finally` macht dann ist das mit `None` und dem Test auch unnötig. Man würde einfach *vor* dem ``try`` die Datei öffnen und das Datei-Objekt an einen Namen binden, dann kan man auch sicher sein dass das Objekt im ``finally``-Zweig existiert.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Ich habe mir mal deine Anmerkung zum Thema with-Anweisung zur Herzen genommen und es wie folgt umgesetzt.

Code: Alles auswählen

        setting_folder = unicode(os.path.abspath(os.path.join('licences', 'Licence GPL2.txt')), "UTF-8")
        try:
            with open(setting_folder) as f:
                        licence_gpl2 = f.read()
                        self.ui_pp_about.textEditLicence.setText(licence_gpl2)
            print("\n\nRead licence-file from: " + setting_folder)
        except (IOError, ValueError):
            print "An I/O error or a ValueError occurred"
        except:
            print "An unexpected error occurred"
            raise
Wie du siehst, habe ich den finally-Block weggelassen. Kann ich durch die with-Anweisung trotzdem sicher sein, dass die Datei jedesmal geschlossen wird? Ich möchte mit dem Arbeiten der Dateien auf eine Nummer sicher gehen, und nach möglichst alle Maßnahmen ergreifen, damit die Datei nicht durch irgendwelche Fehler geöffnet oder gar zerstört wird.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Sophus hat geschrieben:...Kann ich durch die with-Anweisung trotzdem sicher sein, dass die Datei jedesmal geschlossen wird?...
Darüber kann das Python-Tutorial/Doku Aufschluss geben - https://docs.python.org/2/tutorial/inpu ... le-objects
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: es ist übrigens unsinnig, einen Dateinamen utf-8 dekodieren zu wollen. Entweder abspath liefert schon Unicode, dann ist es unnötig, oder abspath liefert den Dateinamen als Bytes, dann erwartet aber auch open Bytes und im schlimmsten Fall in einem anderen Encoding als utf-8.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Danke jerch und Sirius3, wird gleich umgesetzt.

@Sirius3: Ich bin nur davon ausgegangen, dass es Probleme geben könnte, wenn im Pfad bestimmte Zeichen enthalten sind, die außerhalb des ASCII-Wertes liegt, zum Beispiel Umlaute etc. Aber wenn abspath dies schon erleidigt, um so besser :-)

Edit: Wenn ich dich richtig verstanden habe, brauche ich die Dekodierung 'utf-8' nicht anzugeben, aber den Pfad weiterhin als unicode() soll ich weiterhin beibehalten, wenn ich mir unangenehme Fehler ersparen will?

Etwa so:

Code: Alles auswählen

        setting_folder = unicode(os.path.abspath(os.path.join('licences', 'Licence GPL2.txt')))
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Da du Python 2 zu benutzen scheinst ist `unicode(x)` aequivalent zu `unicode(x, 'ascii')`. Mit anderen Worten: Es wird eher zusaetzliche Fehler produzieren.

Du kannst Bytes/str nur dann zu unicode dekodieren, wenn du das Encoding kennst. Einfach UTF-8 zu benutzen ist keine gute Idee. Noch dazu ist es AFAIK nur bei moderneren Linux Systemen das Default-Encoding. Windows benutzt beispielsweise UTF-16.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: wie schon geschrieben, macht ein unicode nichts besser.

@cofi: Windows benutzt UCS2. Da das noch seltener zu Problemen führt als die leidliche 8bit-Kodierungsdiskussion, ist es noch schwieriger Leuten die Probleme deutlich zu machen, auf die sie damit stoßen können.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Sirius3:
Um genau zu sein, nutzt Windows seit Windows 2000 UTF-16 LE mit Unterstützung für surrogate pairs für wchar_t. Betrifft quasi alle `....W()` Funktionen der WinAPI.
Antworten