Seite 2 von 2
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 13:36
von __blackjack__
Ich würde behaupten auch die Version von Sirius3 ist noch nicht korrekt weil ``for line in file:`` nicht zeilenweise lesen muss und das AFAIK auch tatsächlich nicht tut. Das *liefert* zeilenweise, liest aber in grösseren Blöcken und puffert, aus Effizienzgründen. Wenn man tatsächlich garantiert Zeile für Zeile lesen will, muss man explizit `readline()` für jede Zeile benutzen. Zum Beispiel als ``for line in iter(file.readline, b""):``.
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 14:04
von Sirius3
@__blackjack__: ob irgendwo intern gepuffert wird, ist doch für den Anwender egal. `open` liefert immer einen BufferedReader, `readline` verhält sich also genau gleich wie der Iterator.
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 14:14
von __blackjack__
@Sirius3: Dann ist das neu in Python 3. In Python 2 konnte man iterieren und `readline()` nicht mischen weil iterieren gepuffert hat und `readline()` die C-Funktion auf der Datei direkt verwendet hat.
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 14:23
von DasIch
So ganz egal ist internes puffern nicht, den dass führt ja dazu dass es Unterschied gibt zwischen deiner Position aus Perspektive des Betriebssystems und deiner Anwendung. Das muss ja irgendwie in Einklang gebracht werden.
Wenn man die Datei übrigens in "text mode" öffnet bekommt man etwas zurück dass TextIOBase implementiert. .tell() und .seek() auf TextIOBase arbeiten nicht in bytes:
https://docs.python.org/3/library/io.ht ... OBase.seek. Ich denke mal damit wird vermieden dass man invalide Strings durch ein seek an die falsche Stelle produziert.
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 14:39
von Sirius3
@DasIch: es ist in soweit egal, weil ich als Anwender die Dateipositionen des Betriebssystems gar nicht zu Gesicht bekomme.
Und doch, tell und seek arbeiten auch bei Textdateien auf Byteniveau, weshalb es ja zu Problemen kommen kann, wenn man das mischt.
offset must either be a number returned by TextIOBase.tell(), or zero. Any other offset value produces undefined behaviour.
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 16:48
von snafu
Also tell() sollte schon das liefern, was auf "seiner" Abstraktionsebene als aktuelle Position betrachtet wird. Irgendwelche internen Puffer-Positionen hätten da wenig Sinn für den Anwender.
Und was ein Zeichen ist, hängt ja von der Konfiguration des Wrappers ab. Dementsprechend sind das auf unterster Ebene einzelne Bytes, können auf höheren Ebenen aber durchaus Codepoints, d.h. auch mehrere Bytes sein. Wenn man beim zum tell() passenden seek() bleibt, dann spielt das aber ohnehin keine Rolle.
Re: seek() in Python3
Verfasst: Montag 5. Juli 2021, 18:23
von DasIch
Sirius3 hat geschrieben: Montag 5. Juli 2021, 14:39
Und doch, tell und seek arbeiten auch bei Textdateien auf Byteniveau, weshalb es ja zu Problemen kommen kann, wenn man das mischt.
offset must either be a number returned by TextIOBase.tell(), or zero. Any other offset value produces undefined behaviour.
Das sagt ja nur dass eine Nummer erwartet die von .tell() kommt, nicht dass die Number sich auf bytes bezieht. Liest man ein bisschen weiter um zu sehen was .tell() dazu sagt trifft man dann auf:
Return the current stream position as an opaque number. The number does not usually represent a number of bytes in the underlying binary storage.
Re: seek() in Python3
Verfasst: Dienstag 6. Juli 2021, 00:50
von snafu
Nachdem ich nun den Code für seek() und tell() jeweils für den Text- und Binärmodus gesehen habe, würde ich das nur im Binärmodus empfehlen, wie ja schon gezeigt wurde. Im Text-Modus ist das alles sehr kompliziert programmiert, kann in irgendwelchen "Illegal States" landen und wirkt insgesamt jetzt nicht sooo vertrauenserweckend auf mich (nichts für ungut), wobei ich da eh irgendwann aufgegeben habe. f.tell() während man zeilenweise iteriert, wirft sowieso einen OSError im Textmodus, während es im Binärmodus ("rb") klappt wie erwartet. Die Positionsangaben entsprechen im Binärmodus tatsächlich den Bytes, da auf einem Char-Pointer herumgesprungen wird. Keine Ahnung, warum die Doku da so vage ist. Vielleicht wollte man es als Implementierungsdetail belassen und daher nicht näher festlegen.
EDIT: Das soll jetzt nicht heißen, dass tell() im Textmodus aus meiner Sicht grundsätzlich kaputt wäre. Aber in Abhängigkeit von Encoding und Verwendung wären mir das zu viele Unsicherheiten. Soll aber natürlich jeder selbst entscheiden.
Re: seek() in Python3
Verfasst: Dienstag 6. Juli 2021, 04:13
von LukeNukem
DerSuchende hat geschrieben: Montag 5. Juli 2021, 04:58
Wenn auch meine Dateien komplett in den Arbeitsspeicher passen würden, so wollte ich
nicht mit einer Schaufel Erde nach einer Fliege werfen, nur weil genügend Erde vorrätig
ist.
Premature optimization. Du denkst über Dinge nach, die Dein Betriebssystem viel besser kann als Du. Und schießt Dir dabei, Pardon: in Deine eigenen Füße.

Re: seek() in Python3
Verfasst: Dienstag 6. Juli 2021, 05:32
von DerSuchende
Premature optimization. Du denkst über Dinge nach, die Dein Betriebssystem viel besser kann als Du. Und schießt Dir dabei, Pardon: in Deine eigenen Füße.
Nun, da die hier erarbeitete Lösung ja im Prinzip offensichtlich funktioniert, ist der Schuss wohl an den Füßen vorbeigegangen. Es ging ja nur darum, einen etwas intelligenteren Zugriff auszuprobieren. Und wenn es zuletzt nur ein Gedankenspiel bleibt, so ist doch Python dafür genau die richtige Spielwiese

Re: seek() in Python3
Verfasst: Dienstag 6. Juli 2021, 12:40
von DasIch
Naja, so gut sind Betriebssysteme beim Swapping auch nicht, erst recht nicht wenn man das Zugriffspattern nicht kommuniziert. Letztendlich passen Daten aber in der Praxis nahezu immer in den Arbeitsspeicher, die Frage ist nur ob du dir es auch leisten kannst.
Re: seek() in Python3
Verfasst: Dienstag 6. Juli 2021, 21:53
von snafu
@DerSuchende: Ist jetzt eigentlich
diese Lösung dein Favorit? Dir ist schon klar, dass hier immer noch alle Zeilen durchlaufen werden, um die "Breakpoints" zu ermitteln? Die ermittelte Struktur samt Zugriff ist ja nur hilfreich bei langlebigen Programmen und nicht, wenn der gesamte Ablauf immer wieder neu angestoßen wird. Welches von beiden wäre denn dein Szenario? Ist vielleicht nth() bzw nth_or_last() aus dem (externen) more_itertools-Modul schon ausreichend für deine Zwecke? Das Iterable wäre dabei halt dein Stream, der die einzelnen Zeilen liefert. Dann benötigt man kein tell() und seek() für die Wahl einer einzelnen Zeile.
Re: seek() in Python3
Verfasst: Mittwoch 7. Juli 2021, 12:31
von DerSuchende
@DasIch: Beim Arbeitsspeicherverbrauch wollte ich sparsam vorgehen, damit eine Lösungsidee leicht angepasst eventuell auch unter MikroPython einsetzbar bleibt. Allerdings bin ich mir nicht sicher, ob das Python nicht trotzdem hintereinander n Datensätze hereinholt, wenn ich den Datensatz n+1 adressiere. Das muss ich nochmal hinterleuchten. Unter dem Blickwinkel ist es vielleicht doch besser, wenn ich, wie üblich, die Zeilen nacheinander überschreibend einlese, bis Zeile n endlich kommt.
Re: seek() in Python3
Verfasst: Mittwoch 7. Juli 2021, 12:41
von DerSuchende
@snafu: Also so richtig glücklich bin ich mit dieser Vorgehensweise nicht, denn ich bin mir nicht sicher, ob alle Schwierigkeiten beseitigt sind.
Aber da durch das Aufzeichnen der Positionen des Lesezeigers immer auf das Ende einer Zeile gezeigt wird, was ja das einbytige '\n' ist, wird niemals danebengegriffen. Und die dann treffsicher herausgelesene Zeile ist ja dann ja ein String (weil wir ja von einer Textdatei reden) und aus dem kann ich ja durch string[index] jede beliebige Position sauber ansteuern. Aber wenn ich mir überlege wie einfach es ist, mit readlines alles in einer einzigen Liste vorzufinden, mit der man bequem arbeiten kann, überlege ich es mir noch 3x, ob ich mir die Ursprungsidee wirklich antun muss. Aber es war eben so ein verrückter Gedanke aus meiner Vor-Python-Zeit, wo man selbstgeschrienbene Routinen auf Direktzugriffsdateien losgelassen hat, die im dBase-Format organisiert waren.

Re: seek() in Python3
Verfasst: Mittwoch 7. Juli 2021, 13:01
von LukeNukem
DerSuchende hat geschrieben: Montag 5. Juli 2021, 04:58
Wenn auch meine Dateien komplett in den Arbeitsspeicher passen würden, so wollte ich
nicht mit einer Schaufel Erde nach einer Fliege werfen, nur weil genügend Erde vorrätig
ist.
Stattdessen einen Bagger zu bauen, um dann mit dessen Schaufel nach der Fiege zu schlagen, ist jedenfalls... kreativ.

Re: seek() in Python3
Verfasst: Mittwoch 7. Juli 2021, 15:32
von DerSuchende
@LukeNukem: Ok, ich sehe es ein, aber es hat zumindest Erde gespart!
Re: seek() in Python3
Verfasst: Mittwoch 7. Juli 2021, 16:03
von kbr
@DerSuchende: Manchmal ist es gar nicht verkehrt so einzusteigen wie Du, oder zu versuchen das Rad neu zu erfinden, um zu verstehen, wie die Dinge funktionieren. Die Erkenntnis, dass tell und seek im Textmodus keine so gute Idee sind und es besser ist gegen Daten im RAM zu arbeiten, so sie denn hineinpassen, gehört halt dazu. Spannend wird es, wenn die Daten nicht mehr ins RAM passen. Aber auch dafür gibt es bereits fertige Lösungen, die einem das Leben leichter machen können.
Und mit der Erde sollte man immer pfleglich umgehen

Re: seek() in Python3
Verfasst: Mittwoch 7. Juli 2021, 16:29
von __blackjack__
Nur mal so am Rande: es gibt auch Python-Module um DBF-Dateien zu verarbeiten. Das Format ist nicht tot zu kriegen und wird unter anderem im GIS-Bereich noch aktiv verwendet.