Klasse zum auslesen einer Datei
@Ambriador: jetzt fängst Du solangsam an, die richtigen Fragen stellen. Es ist ein Fehler, dass das Table-Objekt keine Attribute titles und cols hat. Du mußt dafür sorgen, dass diese Attribute in »__init__« angelegt werden. Eigentlich sollte man nicht nur durch Zufall merken, dass die Funktion nicht das macht, was man eigentlich denkt, was sie macht (obwohl ich das heute schon um 18:13Uhr und BlackJack um 19:18Uhr geschrieben haben). Sondern man schreibt Tests, die das auch überprüfen.
@Sirius3 wie gesagt, einzeln hatte meine Funktion funktioniert, ich dachte ich muss sie dann einfach nur noch aufrufen und fertig, aus euren Kommentaren ist mir das erst nicht so schlüssig geworden. Dann versuche ich mal in der Nachtschicht was zu basteln.
Also wenn ich das richtig verstanden habe darf ich in der "__init__" nicht unterscheide mit einem "if/else" sondern muss ein objekt erstellen, aber wie lasse ich die "__init__" denn erkennen ob es sich um ein file oder attribute handelt?
-
BlackJack
@Ambriador: Doch, Du musst in der `__init__()` testen und entscheiden was von beiden der Benutzer angegeben hat und was daraufhin passieren muss. Aber egal was der Aufrufer übergibt, *nachdem* die `__init__()` ausgeführt wurde und zum Aufrufer zurück kehrt muss das Objekt in einem benutzbaren Zustand sein. Das heisst die Attribute `headers` und `cols` *dieses* Objekts müssen die entsprechenden Daten enthalten.
Oh je ok, und wofür brauche ich dann die parse_csv? Hört sich so an als ob der Code zum bereitstellen ja schon in die "__init__" muss?
EDIT:
Sorry ist schon spät. Ich denke mal das es so ungefähr aussehen soll?
Jetzt sagt er mir aber "global name "open" is not definded", obwohl das doch zur csv gehört?
EDIT:
Sorry ist schon spät. Ich denke mal das es so ungefähr aussehen soll?
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 = filename
else:
self.file1 = self.parse_csv(filename)
def __str__(self):
return (str(self.titles) +', '+ str(self.cols))
def __eq__(self, other):
return (self.titles, self.cols) == (other.titles, other.cols)
def parse_csv(self, filename):
with open(filename) as f:
reader = csv.reader(f)
header = next(reader)
cols = list(zip(*reader))
return [header, cols]
Endlich habe ich was halbwegs vernünftiges:
Jetzt gibt er mir nur noch die "self.cols" als string und nicht als float 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 = filename
else:
self.file1 = self.parse_csv(filename)
def __str__(self):
return (str(self.titles) +', '+ str(self.cols))
def __eq__(self, other):
return (self.titles, self.cols) == (other.titles, other.cols)
def parse_csv(self, filename):
with open(filename) as f:
reader = csv.reader(f)
self.titles = next(reader)
self.cols = list(zip(*reader))
return [self.titles, self.cols]@Ambriador: das sieht doch jetzt schon mal gut aus. Und es fehlen nur noch ein paar Kleinigkeiten. Achte auf die korrekte Einrückung: 4 Leerzeichen pro Ebene. Setze immer alle Attribute in »__init__«. Für was ist »file1« da? Warum werden »titles« und »cols« nicht immer gesetzt? Für eine klare Schnittstelle sollte eine Methode entweder den internen Zustand eines Objektes ändern, oder etwas zurückliefern, aber nicht beides.
Vielen Vielen Dank für eure Hilfe, ich hab es endlich hinbekommen
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 = filename
else:
self.titles = []
self.cols = []
self.filename = self.parse_csv(filename)
def __str__(self):
return (str(self.titles) +', '+ str(self.cols))
def __eq__(self, other):
return (self.titles, self.cols) == (other.titles, other.cols)
def parse_csv(self, filename):
with open(filename) as f:
reader = csv.reader(f)
self.titles = next(reader)
self.cols = [list(a) for a in zip(*reader)]
self.cols = [[float(b) for b in c] for c in self.cols]
return [self.titles, self.cols]@Ambriador: nein, hast Du nicht. Was Du an das Attribut »filename« bindest ist kein Dateiname.
Daneben liefert »parse_csv« etwas zurück und ändert Attribute. Das sollte nicht sein. Zeile 26 könnte man sich auch sparen. Außerdem solltest Du erklären können, was »zip(*reader)« genau macht, nicht dass Dein Lehrer auf die Idee kommt, Du könntest das irgendwo abgeschrieben haben.
Daneben liefert »parse_csv« etwas zurück und ändert Attribute. Das sollte nicht sein. Zeile 26 könnte man sich auch sparen. Außerdem solltest Du erklären können, was »zip(*reader)« genau macht, nicht dass Dein Lehrer auf die Idee kommt, Du könntest das irgendwo abgeschrieben haben.
Code: Alles auswählen
import csv
class Table:
def __init__(self, titles=None, cols=None, filename=None):
self.titles = titles
self.cols = cols
if filename is not None:
self.parse_csv(filename)
def __str__(self):
return "{}, {}".format(self.titles, self.cols)
def __eq__(self, other):
return self.titles == other.titles and self.cols == other.cols
def parse_csv(self, filename):
with open(filename) as f:
reader = csv.reader(f)
self.titles = next(reader)
self.cols = [[float(b) for b in c] for c in zip(*reader)]
@Ambriador: eine Methode sollte genau eine Sache machen. Z.B. entweder etwas Setzen, oder einen Wert zurückliefern. Macht sie beides, verwirrt das nur, wie Dich z.B., da Du Dich ja gezwungen gefühlt hast, den Rückgabewert an irgendetwas (self.filename) zu binden, was so gar keinen Sinn gemacht hat.
-
BlackJack
Damit die API nicht so stehen bleibt, hier mal ein Beispiel wie so eine Klasse eher aussehen sollte:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import csv
import io
from itertools import izip
CSV_SOURCE = '''\
Zeit,Temperatur
0,15.2
3,16.1
6,14.8
9,20.2
'''
class Table(object):
def __init__(self, headers, columns):
self.headers = headers
self.columns = columns
def __repr__(self):
return '{0.__class__.__name__}({0.headers!r}, {0.columns!r})'.format(
self
)
def __eq__(self, other):
try:
return (
(self.headers, self.columns) == (other.headers, other.columns)
)
except AttributeError:
return NotImplemented
def __ne__(self, other):
return not self == other
def __hash__(self):
return TypeError('unhashable type: ' + self.__class__.__name__)
@classmethod
def read_csv(cls, csv_file):
reader = csv.reader(csv_file)
headers = next(reader)
columns = [map(float, row) for row in izip(*reader)]
return cls(headers, columns)
@classmethod
def load_csv(cls, filename):
with open(filename) as csv_file:
return cls.read_csv(csv_file)
def main():
table_a = Table(
['Zeit', 'Temperatur'], [[0.0, 3.0, 6.0, 9.0], [15.2, 16.1, 14.8, 20.2]]
)
table_b = Table.read_csv(io.BytesIO(CSV_SOURCE))
table_c = Table.load_csv('test.csv')
print(table_a)
print(table_b)
print(table_c)
print(table_a == table_b == table_c)
if __name__ == '__main__':
main()