Seite 1 von 2
Lesen und Schreiben von Klassen in CSV
Verfasst: Dienstag 16. November 2021, 12:47
von zegru
Hallo!
Ich würde gerne eine Liste von Objekten als CSV lesen und schreiben. Wie macht man das in Python am besten? Alles Suchen im Netz und im Forum hat leider nicht geholfen.
Folgenden Beispielcode habe ich bis jetzt:
Code: Alles auswählen
import csv
import sys
class Test:
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return f"Test({self.a}, {self.b})"
# Das hier klappt
x1 = Test(1, 2)
x2 = Test(5, 6)
tests = (x1, x2)
print(tests)
# Das hier leider nicht
csv_writer = csv.writer(sys.stdout)
csv_writer.writerows(tests) # Hier kracht es
Erwarten würde ich hier eigentlich sowas wie
1, 2
5, 6
Leider bekomme ich stattdessen die Fehlermeldung "_csv.Error: iterable expected, not Test". Etwas kryptisch, aber im Nachhinein verständlich, dass es kracht.
Wie kann man CSV Dateien am besten in Python lesen und schreiben?
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Dienstag 16. November 2021, 13:11
von kbr
Wenn du Listen von Objekten speichern und später wieder lesen möchtest, bietet sich pickle (aus der stdlib) an. Das funktioniert wunderbar, solange man die Warnungen beherzigt.
Wenn es unbedingt csv sein muss, hast du mehr Arbeit: einerseits pro Instanz alle Attribute in einem Iterable vorbereiten, welches dann von der csv-library akzeptiert wird. Und andererseits die Objekte wieder instanziieren, wenn die csv-Daten gelesen werden.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Dienstag 16. November 2021, 13:39
von __blackjack__
@zegru: Du musst halt aus Deiner Liste (das sollte eher kein Tupel sein) aus `Test`-Objekten etwas machen, was `writerows()` erwartet. Und das ist ein iterierbares Objekt (hast Du) mit einem iterierbaren Objekt pro Datensatz, das die Zellenwerte liefert. Deine `Test`-Objekte sind nicht iterierbar, darum die Fehlermeldung.
Code: Alles auswählen
#!/usr/bin/env python3
import csv
import sys
from attr import astuple, attrib, attrs
@attrs(frozen=True)
class Test:
a = attrib()
b = attrib()
def main():
tests = [Test(1, 2), Test(5, 6)]
print(tests)
csv.writer(sys.stdout).writerows(map(astuple, tests))
if __name__ == "__main__":
main()
Ausgabe:
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Donnerstag 18. November 2021, 21:44
von zegru
Ich habe das versucht, aber bei mir klappt 'attr' ganz und gar nicht.
Ich verwende ein virtuelles Environment, in das ich das Paket 'attr' mit pip installiert habe:
Das Programm funktioniert bei mir gar nicht: Ständig beschwert sich Python, dass etliche Methoden nicht definiert sind. Kein Wunder, denn wenn ich das hier tippe:
Code: Alles auswählen
python
Python 3.9.5 (default, May 11 2021, 08:20:37)
[GCC 10.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import attr
>>> import inspect
>>> inspect.getmembers(attr, predicate=inspect.ismethod)
[]
Was nun?
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Donnerstag 18. November 2021, 21:49
von __deets__
Nun gibst du mal “import attr; print(attr)” ein, und zeigst, was dabei herumkam.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Donnerstag 18. November 2021, 21:52
von zegru
Code: Alles auswählen
>>> print(attr)
<module 'attr' from '/home/chris/devel/test/venv/lib/python3.9/site-packages/attr.py'>
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Donnerstag 18. November 2021, 22:04
von __blackjack__
Das ist das falsche Package. Beziehungsweise das ist gar keines sondern ein Modul. Das Python-Package heisst `attr`, das Python Package Index Package das man installieren muss heisst `attrs` — mit "s" am Ende.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Donnerstag 18. November 2021, 22:04
von __deets__
Laut
https://github.com/python-attrs/attrs/b ... n/setup.py heißt das Paket attrs. Und ist nicht nur eine Datei. Was auch immer du dir da eingefangen hast - das scheint falsch.
Edit: das hier:
https://github.com/denis-ryzhkov/attr - ist das falsche.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Donnerstag 18. November 2021, 22:22
von zegru
Nach einem 'pip uninstall attr; pip install attrs' klappt es jetzt. Danke!
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 06:44
von zegru
Ich habe mir die Doku von attr angesehen. Will man das nicht immer verwenden?
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 07:34
von sparrow
Was ist die Substanz der Frage?
So ist die Antwort: Warum sollte man es verwenden, wenn man die Funktionalität nicht braucht?
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 08:29
von zegru
Es wird unter anderem die __init__ und die __repr__ Methode automatisch erstellt. Auch wenn man __repr__ nicht von vorne herein benötigt, habe ich sie schon im Nachhinein oft zum Debuggen erzeugt.
Meine generelle Meinung, dass trotz Zen es Python gut täte, wenn es etwas impliziter wäre. Eigentlich wäre es gut, wenn es direkt in die Sprache eingebaut wäre.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 12:36
von __blackjack__
@zegru: Also ich will das immer benutzen.

Unter anderem wegen der `__init__()` und der `__repr__()` und dann auch wegen `frozen`, `__eq__()`, `__ne__()`, `__lt__()`, den ganzen anderen magischen Vergleichsmethoden, und `__hash__()` die man dann nicht selbst schreiben muss.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 13:46
von __deets__
Hynak, der Autor, hat mal einen Blogpost oder Vortrag darueber gehalten, warum er das nicht in die Standardbibliothek einbauen will. Da ging es im Grunde um die Entkopplung von Release-Zyklen.
Wenn man will, kann man ja aber auch
https://docs.python.org/3/library/dataclasses.html benutzen. Das ist vielleicht nicht ganz so umfangreich, aber vieles kann es eben auch schon.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 17:01
von narpfel
@zegru: Noch als Hinweis, warum dein `inspect`-Aufruf eine leere Liste zurückgegeben hat: Du hast mit `inspect.ismethod` gefiltert, aber ein Modul hat (weil es keine Klasse ist) logischerweise keine Methoden, sondern nur Funktionen. IMHO wäre es auch einfacher gewesen, einfach `dir(attr)` zu benutzen.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 19:41
von zegru
Noch eine Frage, in diesem Zusammenhang, wo ebenfalls alles Recherchieren und Probieren nichts geholfen hat: Ich möchte die Objekte nicht nur schreiben, sondern auch lesen, und sie kommen dann in eine Datenbank, und verwenden hierfür SQLAlchemy. Habt ihr einen weiteren Tipp für mich?
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 20:00
von __deets__
Das geht nur, indem du zusätzlich den Typnamen speicherst, und eine Factory für die Objekte baust. Sowas kann man zb mit Metaklassen machen.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Freitag 19. November 2021, 20:37
von __blackjack__
Hm, bei SQLAlchemy hat man dann doch schon die ORM-Klassen, beziehungsweise kann man sich ja Mapper auf vorhandene Klassen erstellen.
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Sonntag 21. November 2021, 12:14
von zegru
Hm, ich sehe schon: Ich muss mich noch tiefgehender mit Python beschäftigen, Kenntnisse anderer Programmiersprachen erweitert um Comprehensions reicht nicht aus. Die Python-Welt ist doch größer als vermutet. Vor allem das Konzept der Metaklassen ist mir ziemlich neu. Gibt es da eine Einführung, die nicht bei 0 anfängt? Also die nicht unbedingt damit anfängt, wie man den Rechner einschaltet und Python installiert? Und auch keine, die bei 150 anfängt ("Was unterscheidet dieses obskure Modul von jenem?").
Ich habe einstweilen mal probiert, attrib und SQLAlchemy zu verheiraten. Leider kein Erfolg bis jetzt.
Geht, aber halt ohne attr:
Code: Alles auswählen
class Test(Base):
__tablename__ = "test"
a = Column(Integer, primary_key=True)
b = Column(Integer)
Der naive Ansatz mit attr geht nicht, weil angeblich kein Primärschlüssel definiert ist:
Code: Alles auswählen
@attrs(frozen=True)
class Test(Base):
__tablename__ = "test"
a = attrib(Column(Integer, primary_key=True))
b = attrib(Column(Integer))
Re: Lesen und Schreiben von Klassen in CSV
Verfasst: Sonntag 21. November 2021, 12:32
von __deets__
Das man mit SQLAlchemy CSV lesen/schreiben kann, halte ich für unwahrscheinlich. Und eine Kombination mit attrs ist nicht sinnvoll, SA selbst ist ja hoch declarative, und baut sich eigene Klasse - das kommt sich alles in die Quere. - ok, snafu hat gezeigt, dass es geht. Ich finde es immer noch etwas komisch, aber gut.
Statt Metaklassen sind vielleicht auch eher Klassendekoratoren (wie attrs selbst sie benutzt) eine gute Wahl. Damit kannst du zb die erzeugte Methode zum iterieren der Attribute so ummanteln, dass sie vorher noch den Klassennamen ausgibt. Und gleichzeitig eine globale Registry für die genannte Factory füttert, du musst ja eine Zuordnung von Klassenname auf Klasse hinbekommen, und die restlichen Werte dann Typwandeln und einlesen basierend auf der Attribut-Deklaration.
Das ist aber auch alles ganz schön viel Maschinerie. Über wieviele Klasse reden wir denn hier? Denn man kann das bei einigen wenigen ja auch einfach erstmal “zu Fuß” programmieren. Die ganze Meta-Magie ist fein, aber auch oft etwas undurchdringbar.