Seite 1 von 2
Klasse zum auslesen einer Datei
Verfasst: Freitag 27. Januar 2017, 09:56
von Ambriador
Hallo an alle,
ich komme leider wieder nicht bei einer Aufgabe weiter
Wir sollen mittels einer Klasse eine CSV Datei auslesen und die Werte wieder zurückgeben.
Code: Alles auswählen
import csv
class Table:
def __init__(self, titles=None, cols=None, filename = None):
self.titles = titles
self.cols = cols
self.filename = filename
def __str__(self):
return (str(self.titles) +', '+ str(self.cols))
def __eq__(self, other):
try:
return (self.titles, self.cols) == (other.titles, other.cols)
except AttributeError:
return NotImplemented
def parse_csv(self, filename):
with open(filename, newline='') as csvfile:
spamreader = csv.reader(csvfile)
for row in spamreader:
return row
"__str__" soll zu Ausgabe der Attribute dienen, "__eq__" vergleicht zwei verschiedene Eingaben, und "parse_csv" bekommt einen Dateinamen übergeben und soll die Zeilenüberschriften und Spalten auslesen und diese ans Objekt zurückgeben.
Wenn ich die Klasse allerdings mit einer Datei aufrufen, springt er direkt in die "__str__" Methode, wie kann man das ändern?
Viele Grüße
Re: Klasse zum auslesen einer Datei
Verfasst: Freitag 27. Januar 2017, 10:25
von sebastian0202
Hallo,
ich habe deine Klasse mal in python2.6 genutzt und habe keine Probleme.
CSVReader = Table()
print CSVReader.parse_csv('local.csv')
Und anschließend printet er mir die CSV.
Auch wenn ich die Klasse mit Table('','','local.csv') erstelle, bekomme ich keinen Fehler.
Zeige mal deinen Quellcode, der zu deinem Fehler führt.
Re: Klasse zum auslesen einer Datei
Verfasst: Freitag 27. Januar 2017, 10:44
von Sirius3
@Ambriador: die parse_csv-Methode macht so keinen Sinn. Es wird nichts von der Klasse benutzt. Das ist eigentlich eine ganz normale Funktion. Ich würde ja erwarten, dass das eine Klassenmethode ist, die ein neues Table-Objekt zurückliefert. In __eq__ erzeugst Du Tuple, statt and zu verwenden.
Wie sieht denn der Aufruf aus?
Re: Klasse zum auslesen einer Datei
Verfasst: Freitag 27. Januar 2017, 15:53
von Ambriador
Ein Aufruf wäre z.b.:
Code: Alles auswählen
titles = ["Zeit", "Temperatur"]
my_table3 = Table(titles, [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]])
print(my_table3)
my_table3_parsed = Table(filename = "simple_example.csv")
print(my_table3_parsed)
Die Ausgabe sieht dann so aus:
Code: Alles auswählen
['Zeit', 'Temperatur'], [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]]
None, None
In der CSV Datei stehen die selben Werte wie bei my_table3 gegeben. Die Formatierung, bzw "aufschreiben", der Ausgabe von "parse_csv" stimmt zwar auch noch nicht, aber ich bekomme mit einer Datei ja noch nicht mal das raus was ich in "parse_csv" geschrieben habe.
Wenn ich "parse_csv" so einzeln aufrufe, bekomme ich auch ein Ergebnis, aber hier in der Klasse springt er mit dem Dateiname direkt zur "__str__" Methode.
Mit dem Aufruf von "__eq__" gabs keine Probleme.
Re: Klasse zum auslesen einer Datei
Verfasst: Freitag 27. Januar 2017, 16:55
von BlackJack
@Ambriador: Innerhalb der Klasse wird nirgendwo hin gesprungen. Die `__str__` wird durch das `print()` in der letzten Zeile des Hauptprogramms aufgerufen. Und da die `__init__()` nichts weiter anstellt mit `filename` als es an ein Attribut zu binden wird ``None, None`` ausgegeben, denn das sind ja die Werte die in der `__init__()` an die Attribute `titles` und `cols` gebunden wird wenn man für die gleichnamigen Argumente nichts übergibt. Wieso erwartest Du das auf magische Weise `parse_csv()` aufgerufen werden sollte? Und selbst wenn das der Fall wäre, dann würde an die beiden Attribute `titles` und `cols` trotzdem nichts anderes gebunden, denn die Methode tut das ja letztendlich nicht.
`__eq__()` hast Du hoffentlich nicht direkt aufgerufen sondern den ``==``-Operator verwendet‽
Dir Schnittstelle von der `__init__()` ist unschön. Ich würde da auch eher eine API wie von Sirius3 beschrieben, erwarten.
Warum nennst Du das Reader-Objekt `spamreader`? `spam`‽
Re: Klasse zum auslesen einer Datei
Verfasst: Freitag 27. Januar 2017, 17:48
von pixewakb
spamreader ist der Beispielname im Tutorial...
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 10:57
von Ambriador
Hatte da gar nicht dran gedacht das "__str__" durch das "print()" aufgerufen wird.
Dann bekomme ich den Error für "assert my_table3_parsed == my_table3" auch nur deswegen weil die parse_csv nicht das passende Ergebnis ausgibt.
Das was aus der Datei gelesen wird soll so aussehen:
Code: Alles auswählen
my_table3 = (["Zeit", "Temperatur"], [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]])
Bekomme es aber nicht richtig hin die csv passend "auszulesen".
"['Zeit', 'Temperatur']" bekomme ich mit "next(reader)", aber wie schaffe ich es das er die erste Spalte in eine Liste, und die zweite Zeile seperat in eine Liste packt?
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 11:06
von BlackJack
@Ambriador: Schleifen und die `zip()`-Funktion (oder `itertools.izip()` in Python 2) oder die `zip()`-Funktion (plus `list()` in Python 3) mit einem ”Trick” beim Aufruf von `zip()` für das transponieren von Zeilen und Spalten.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 17:21
von Ambriador
Hab jetzt endlich was hinbekommen, allerdings arbeitet er "parse_csv" immernoch nicht ab.
Ich muss ja die __init__ ändern so wie ich das verstanden habe, aber wie?
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 17:46
von Sirius3
@Ambriador: und was hast Du hinbekommen?
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 17:50
von Ambriador
MIt Hilfe konnte ich die parse_csv so hinbekommen das sie eine richtige Ausgabe hinbekommt, und auch den Aufruf hab ich hinbekommen, aber jetzt bekomme ich den vergleich nicht hin.
Code: Alles auswählen
import csv
class Table:
def __init__(self, titles=None, cols=None, filename = None):
if filename is None:
self.titles = titles
self.cols = cols
self.filename = None
else:
self.filename = filename
self.parse_csv(filename)
def __str__(self):
return (str(self.titles) +', '+ str(self.cols))
def __eq__(self, other):
if self.filename == None:
return (self.titles, self.cols) == (other.titles, other.cols)
else:
return self.filename == other
def parse_csv(self, filename=None):
a=open("simple_example.csv",'r')
timel,templ,count=[],[],0
final=[]
for l in a:
c=l.split(',')
if count >=1:
timel.append(float(c[0]))
templ.append(float(c[1]))
if count==0: #this is just append the header in the fianl list
c[1]=c[1][:-1]
final.append(c)
count+=1
final.append([timel,templ])
final=tuple(final)
return final
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 18:13
von Sirius3
@Ambriador: was ist denn Dein Ziel? Denn aus dem Code wird das nicht klar. Wird filename angegeben, wird ein Instanz mit komplett anderer Funktionalität erzeugt, als wenn nicht. parse_csv hat mit der Klasse an sich immer noch nichts zu tun. filename wird nicht verwendet, a, c oder l sind schlechte Variabelnamen, weil sie nichts aussagen. Was soll die 1 bei time1 und temp1? Die for-Schleife macht nichts, weil count nie >= 1 wird. Dass open nicht definiert ist, deutet darauf hin, dass was ziemlich schräges gemacht hast.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 18:17
von Ambriador
Sorry hatte mich auch verschrieben, das mit dem "open" fehler kommt nicht mehr vor.
Ich will/soll den Inhalt einer Datei mit einer gegebenen Liste vergleichen, wobei die Datei genau so aussieht wie die Liste:
Code: Alles auswählen
titles = ["Zeit", "Temperatur"]
filename1 = "simple_example.csv"
my_table3 = Table(titles, [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]])
my_table3_parsed = Table(filename = "simple_example.csv")
assert my_table3_parsed == my_table3
Ich verzweifle schon ein paar Tage an der Aufgabe und komme nicht wirklich weiter, deswegen bin ich froh das überhaupt mit parse_csv hinbekommen zu haben.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 18:53
von Ambriador
Sieht leider nicht gut aus und ist auch bestimmt total unübersichtlich aber ich wollte mal schauen was er denn nun ausgibt für die Funktion parse_csv bzw den code der dadrin steht. Da ich leider echt nicht weiter weiss ist hier mein letzter Stand, über jede Hilfe wäre ich echt mega dankbar. Wenn ich den Code aus der parse_csv einzeln benutze und auf eine Datei anwende gibt er die Datei richtig aus:
Code: Alles auswählen
import csv
class Table:
def __init__(self, titles=None, cols=None, filename = None):
if filename is None:
self.titles = titles
self.cols = cols
self.filename = None
else:
self.filename = filename
self.parse_csv(filename)
def __str__(self):
if self.filename == None:
return (str(self.titles) +', '+ str(self.cols))
else:
return str(self.parse_csv(self.filename))
def __eq__(self, other):
if self.filename == None:
return (self.titles, self.cols) == (other.titles, other.cols)
else:
return self.parse_csv(self.filename) == (other.titles, other.cols)
def parse_csv(self, filename):
a=open(filename,'r')
timel,templ,count=[],[],0
final=[]
for l in a:
c=l.split(',')
if count >=1:
timel.append(float(c[0]))
templ.append(float(c[1]))
if count==0: #this is just append the header in the fianl list
c[1]=c[1][:-1]
final.append(c)
count+=1
final.append([timel,templ])
final=tuple(final)
return final
my_table1 = Table(["title1", "title2"], [["l1"], ["l2"]])
print(my_table1)
assert my_table1.titles[0] == "title1"
assert my_table1.titles[1] == "title2"
assert my_table1.cols[0] == ["l1"]
assert my_table1.cols[1] == ["l2"]
my_table2 = Table(["title1", "title2"], [["l1"], ["l2"]])
assert my_table2 == my_table1
titles = ["Zeit", "Temperatur"]
filename1 = "simple_example.csv"
my_table3 = Table(titles, [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]])
my_table3_parsed = Table(filename = "simple_example.csv")
print(my_table3)
print(my_table3_parsed)
assert my_table3_parsed == my_table3
Die Ausgabe sieht dann so aus:
Code: Alles auswählen
['title1', 'title2'], [['l1'], ['l2']]
['Zeit', 'Temperatur'], [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]]
([[], []],)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-225-53aa68bfdaf6> in <module>()
60 print(my_table3_parsed)
61
---> 62 assert my_table3_parsed == my_table3
AssertionError:
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 19:18
von BlackJack
@Ambriador: Es ist ganz sicher *nicht* gewollt das Du da im Grunde zwei verschiedene Datentypen in `Table` vereinst und in jeder Methode nicht nur immer zwischen beiden mit ``if`` unterschieden wird, sondern auch noch bei jeder Operation die Datei neu eingelesen wird.
Die `parse_csv()`-Methode sollte auch einen Einfluss auf den Zustand des Objekts haben, damit das überhaupt eine Methode ist. `__str__()` und `__eq__()` sollten nur auf `self.titles` und `self.cols` operieren und kein ``if``/``else`` enthalten. Den Methoden sollte es egal sein ob die Werte für die Tabelle beim erzeugen übergeben wurden, oder ob sie aus einer Datei geladen wurden.
Warum verwendest Du das `csv`-Modul nicht mehr? Ausserdem gibt es sicher Punktabzug weil die Methode nur mit zwei Spalten klar kommt. Das soll ganz sicher generischer sein, also mit jeder Tabelle mit Kopfzeile und Zahlen mit beliebig vielen Zeilen und Spalten klar kommen.
Die verschachtelten ``if``\s und der Wert von `count` — das funktioniert so *überhaupt nicht*. Beschreib mal den Programm ablauf bis zu dem ``count+=1`` das erste mal ausgeführt wird!
Werd bei Gelegenheit mal dieses unsinnige `my_` vor den ganzen Namen für die Tabellen los. Was soll das? Das bringt Null Informationsgewinn beim lesen.
`a`, `l`, und `c` sind keine guten Namen. Da muss man jetzt raten was die bedeuten sollen?
Die Datei wird geöffnet, aber nicht wieder geschlossen.
Wenn man `__eq__()` implementiert, dann sollte man unbedingt auch `__neq__()` implementieren. Was ja super simpel ist wenn man `__eq__()` schon hat. Und `__hash__()` müsste man dann auch gleich überschreiben damit die Werte sich nicht ”komisch” verhalten.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 19:27
von Ambriador
Alles ab Zeile 40 ist so vorgegeben, da habe ich leider keinen Einfluss drauf, deswegen werde ich die Punkte übergehen. Desweiteren sollen wir keine weiteren Methoden einbauen bis auf die die gegeben sind.
Aber wenn ich z.b. ein "assert my_table3_parsed == my_table3" aufrufe, dann springt er ja automatisch in die "__eq__" Methode, wenn ich da dann nur eine Bearbeitung für die Attribute drin habe bekomme ich ja nen False oder nicht?
Das csv Modul benutze ich nicht mehr weil ich damit nie zu einer Lösung gekommen bin, das ist das einzige was läuft. Wie gesagt, einzeln bekomme ich das passende Ergebnis:
Code: Alles auswählen
a=open("simple_example.csv",'r')
timel,templ,count=[],[],0
final=[]
for l in a:
c=l.split(',')
if count >=1:
timel.append(float(c[0]))
templ.append(float(c[1]))
if count==0: #this is just append the header in the fianl list
c[1]=c[1][:-1]
final.append(c)
count+=1
final.append([timel,templ])
final=tuple(final)
print(final)
Code: Alles auswählen
(['Zeit', 'Temperatur'], [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]])
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 20:55
von BlackJack
@Ambriador: Du bekommst beim `__eq__()` nur ein `False` wenn die Attribute nicht gleich sind. Das sollten sie aber sein, falls nicht hast Du etwas falsch gemacht.
Einzeln hast Du aber auch etwas anderes als in der `read_csv()`-Methode denn dort ist der Programmablauf anders. Das ``count+=1`` kann dort niemals erreicht werden. Deswegen fragte ich ja nach einer Beschreibung wie Du denkst das das ausgeführt werden sollte.
Dass es so geht, aber mit dem `csv`-Modul nicht, kann nicht sein. Denn letztendlich machst Du die Arbeit des `csv`-Moduls, allerdings ohne die ganzen Sonderfälle des Formats zu berücksichtigen.
Letztendlich ist das was Du da machst aber nur sehr schwer nachvollziehbar und wie gesagt, bestimmt nicht generisch genug für die erwartete Lösung. Das macht nicht den Eindruck als wärst Du da systematisch heran gegangen. Also das Problem in kleinere Teilprobleme zu zerlegen und die dann getrennt und gezielt zu lösen.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 21:27
von Ambriador
@BlackJack, aber wenn ich nur "(self.titles, self.cols) == (other.titles, other.cols)" in der "__eq__" habe, dann muss ich doch zwangsläufig auch etwas haben wenn ich "my_table3_parsed == my_table3" vergleiche, da eines der Objekte ja nicht über "title" und "cols" definiert wird?
Ich hab es schon mit dem csv-Modul versucht, bekomme aber immer etwas wie "list object is not callable", deswegen war ich froh das es mit dem jetzigen Aufruf endlich geklappt hatte, außerhalb der Klasse.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 21:34
von BlackJack
@Ambriador: Beide Objekte werden über `titles` und `cols` bestimmt. Wenn sie das nicht sind, dann ist *das* der/ein Fehler. Der einzige Unterschied ist wie diese Attribute zustande kommen. Das ist zum Zeitpunkt des Vergleichs aber egal, denn dann haben sie ja die gleichen Werte.
Re: Klasse zum auslesen einer Datei
Verfasst: Samstag 28. Januar 2017, 21:53
von Ambriador
@BlackJack
wenn ich nur "(self.titles, self.cols) == (other.titles, other.cols)" stehen lasse bekomme ich den Error "'Table' object has no attribute 'titles'". Ich sehe auch gerade das er für die aus der Datei gelesenen Liste nur "([[], []],)" ausgibt, also funktioniert die "parse_csv" doch nicht richtig
