Seite 1 von 1

CSV-Reader

Verfasst: Dienstag 29. März 2005, 09:36
von hehejo
Dank kompetenter Hilfe hier (http://python.sandtner.org/viewtopic.php?t=2992) kann ich dieses hier präsentieren:

Code: Alles auswählen

def csv(filename):
    f = open(filename, "r")
    bezeichner = f.readline().rstrip("\n").split(";")
    content = f.readlines()
    f.close()
    mappe = {}
    for line in content:
      if line.startswith("#"):
        continue
      line = line.rstrip("\n")
      for key, value in zip(bezeichner, line.split(";")):
        mappe[key] = value
      yield mappe
    #raise StopIteration
Zwar gibt es das Modul csv, aber .. naja ich wollt auch mal wieder was programmiern.

Kritik bitte äußern!

edit: Danke für die Hinweise Leonidas

Verfasst: Dienstag 29. März 2005, 11:38
von Leonidas
Es fehlt ein Doppelpunkt nach dem 1. for (ich weiß, Kleinigkeit) und sowie ich das sehe muss StopIteration nicht explizit aufgerufen werden, da Generatoren das immer von selbst tun, wenn sie am Ende sind (ist aber auch nicht so wild).

Verfasst: Dienstag 29. März 2005, 21:40
von BlackJack
Ich würd's so schreiben:

Code: Alles auswählen

def csv(lines, separator=';', comment_char='#'):
    line_iterator = iter(lines)
    header = line_iterator.next().rstrip().split(separator)
    for line in line_iterator:
        if not line.startswith(comment_char):
            yield dict(zip(header, line.rstrip().split(separator)))

csv_file = open('filename', 'r')
content = list(csv(csv_file))
csv_file.close()
Das herausziehen des Dateiöffnens hat den Vorteil, dass es nun mit jedem "iterable" funktioniert, das Zeilen liefert und nicht nur mit Dateien.

Ausserdem gebe ich nicht immer das selbe Dictionary zurück. Das kann zu sehr komischen Ergebnissen führen wenn man nicht damit rechnet. Zum Beispiel wäre bei 10 Datensätzen in `content` 10 mal das gleiche Dictionary mit dem letzten Datensatz als Inhalt.

elegante Lösung

Verfasst: Mittwoch 30. März 2005, 08:25
von hehejo
oh - das ist eine elegante Lösung.

Danke! Da werde ich mir wieder etwas rauszeiehen können.

Code: Alles auswählen

yield dict(zip(header, line.rstrip().split(separator)))
An sowas hab ich noch garnicht gedacht.
Wunderbar!

Verfasst: Mittwoch 30. März 2005, 23:03
von BlackJack
Vielleicht sollte man das Filtern von Kommentarzeilen und evt. auch Leerzeilen auch aus der Funktion herausnehmen. In der Form werden jetzt nur Kommentare nach der Zeile mit den Bezeichnern ignoriert, aber gerade ganz am Anfang einer Datei würde man ja Kommentare oder eine Beschreibung der folgenden Daten erwarten.

Code: Alles auswählen

from itertools import ifilter
import pprint

def csv(lines, separator=';'):
    line_iterator = iter(lines)
    header = line_iterator.next().rstrip().split(separator)
    for line in line_iterator:
        yield dict(zip(header, line.rstrip().split(separator)))

def make_linetest(comment_start='#'):
    def is_content_line(line):
        line = line.strip()
        return line and not line.startswith(comment_start)
    return is_content_line

csv_data = ('# Some names.\n',
            'name;surname;profession\n',
            ' # Another comment.\n',
            'Dagobert;Duck;Zillionaire\n',
            '  \t \n',
            'Guido;van Rossum;BDFL\n',
            '\n',
            '# Data ends here.\n')
content = list(csv(ifilter(make_linetest(), csv_data)))
pprint.pprint(content)
Ich geb zu, mit dem Closure habe ich es ein wenig übertrieben. Statt `make_linetest()` hätte es auch eine einfache Funktion mit hart kodiertem Kommentarzeichen getan. :-)

Verfasst: Freitag 1. April 2005, 09:24
von hehejo
BlackJack hat geschrieben:Vielleicht sollte man das Filtern von Kommentarzeilen und evt. auch Leerzeilen auch aus der Funktion herausnehmen. In der Form werden jetzt nur Kommentare nach der Zeile mit den Bezeichnern ignoriert, aber gerade ganz am Anfang einer Datei würde man ja Kommentare oder eine Beschreibung der folgenden Daten erwarten.
Das leuchtet mir ein.

Doch was ist das hier alles?

Code: Alles auswählen

from itertools import ifilter
import pprint
Was zur Hölle macht diese Funktion? Das verstehe ich jetzt im Moment nicht. Aber so wie ich das sehe, ist es eine Funktion, die man dann zum Sortieren/ Auswählen nutzen kann.

Code: Alles auswählen

def make_linetest(comment_start='#'):
    def is_content_line(line):
        line = line.strip()
        return line and not line.startswith(comment_start)
    return is_content_line
Könnsest du mir bitte dieses "return xxx and not xxx.xxx" erklären?
BlackJack hat geschrieben: Ich geb zu, mit dem Closure [...]
Closure? *öhmm* hast da mal nen Link zu?

Ich sehe schon: Python hat noch viele Feinheiten die ich entdecken kann!

Verfasst: Freitag 1. April 2005, 09:57
von Leonidas
hehejo hat geschrieben:Doch was ist das hier alles?

Code: Alles auswählen

from itertools import ifilter
import pprint
itertools - zum effizienten erstellen von Iteratoren. ifilter() ist die Iteratoren-Version von filter().
pprint Prettyprint. Damit man was hübsches zu sehen hat :)

Verfasst: Freitag 1. April 2005, 23:04
von BlackJack
hehejo hat geschrieben:

Code: Alles auswählen

def make_linetest(comment_start='#'):
    def is_content_line(line):
        line = line.strip()
        return line and not line.startswith(comment_start)
    return is_content_line
Könnsest du mir bitte dieses "return xxx and not xxx.xxx" erklären?
Vielleicht wird's etwas klarer wenn ich Klammern setze:

Code: Alles auswählen

return (line and (not line.startswith(comment_start)))
Der Ausdruck nach ``return`` wird ausgewertet und zurückgegeben. Fangen wir mal hinten an: ``line.startswith(comment_start)`` gibt `True` oder `False` zurück. Mit ``not`` wird dieser Wert negiert, also als `False` wird `True` und umgekehrt. Und dieser Wahrheitswert wird mit `line` und-Verknüpft. Dazu muss man wissen, das eine Zeichenkette mit 0 Zeichen `False` ist und alles andere `True`. Das gleiche gilt übrigens für Listen, Tupel, Sets und alles andere auf das man `len()` anwenden kann. Noch etwas ausführlicher hätte man also auch das hier schreiben können:

Code: Alles auswählen

return ((len(line) != 0) and (not line.startswith(comment_start)))
BlackJack hat geschrieben: Ich geb zu, mit dem Closure [...]
Closure? *öhmm* hast da mal nen Link zu?
Klar: http://de.wikipedia.org/wiki/Closure

Python wird auf der Seite sogar erwähnt, die Beispiele sind leider in Perl :shock:

Und hier noch die englische Seite zum Thema http://en.wikipedia.org/wiki/Closure_(computer_science)

Verfasst: Montag 4. April 2005, 09:00
von hehejo
Vielen Dank!

Ich hab mir das ganze gestern noch mal durch den Kopf gehen lassen und bin wieder etwas klüger.

Gibt schon viele interessante Lösungen in Python...

Ich freu mich!