Objektorientierte Programmierung - CSV Datei auslesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Mucku
User
Beiträge: 7
Registriert: Mittwoch 17. August 2011, 22:37

Hallo zusammen!
Habe ein Problem mit folgendem Quellcode. Die Aufgabe besteht darin eine CSV Datei(in Excel erstellt) auszulesen und die einzelnen Einträge in entsprchende Klassenvariablen einzuspeichern. Ich kann die Daten auch richtig einlesen, aber nicht mehr vernünftig wiedergeben. Ich versteh einfach die Meldung nicht:
[<__main__.Datensatz object at 0x0239AEF0>, <__main__.Datensatz object at 0x0239AEF0>, <__main__.Datensatz object at 0x0239AEF0>, <__main__.Datensatz object at 0x0239AEF0>, <__main__.Datensatz object at 0x0239AEF0>]

Wenn jemand kurz Zeit hätte und mal darüber gucken könnte:

Code: Alles auswählen

class Datensatz(object):
    def __init__(self):
        
        self.__nummer = 0
        self.__datum = ''
        self.__zeit = ''
        self.__idx = 0
        self.__aussen = 0
        self.__vorlauf = 0
        self.__ruecklauf = 0
       
    def setNummer(self, value):
        self.__nummer = value
    def getNummer(self):
        return self.__nummer
    
    def setDatum(self, string):
        self.__datum = string
    def getDatum(self):
        return self.__datum
    
    def setZeit(self, string):
        self.__zeit = string
    def getZeit(self):
        return self.__zeit
            
    def setIdx(self, value):
        self.__idx =value
    def getIdx(self):
        return self.__idx
    
    def setAussen(self, float):
        self.__aussen = float
    def getAussen(self):
        return self.__aussen
        
    def setVorlauf(self, float):
        self.__vorlauf = float
    def getVorlauf(self):
        return self.__vorlauf
    
    def setRuecklauf(self, string):
        self.__ruecklauf = string
    def getRuecklauf(self):
        return self.__ruecklauf
        
               
def readDaten(filename):
    Datenliste = []
    tmpDatensatz = Datensatz()#Variable tmpDatensatz der Form Datensatz, vgl klasse oben
    DatenFile = open(filename, 'r')
    Messdaten = DatenFile.readlines()#Auslesen der Datei
    DatenFile.close()
    for line in Messdaten:
        a = (str(line)).split(';')        # die folgenden 5 Zeilen sind nur dafür da Daten in de Tabelle richtig auszulesen, sie könnten bei einer anderen Tabelle auchweggelassen werden
        b = (str(a[0])).split()
        del a[0]
        a.insert(0,b[0])
        a.insert(1,b[1])             #es entsteht Liste mit 6 Einträgen, die anschließend zugewiesen werden
        tmpDatensatz.setDatum(a[0])
        tmpDatensatz.setZeit(a[1])
        tmpDatensatz.setIdx(a[2])
        tmpDatensatz.setAussen(a[3])
        tmpDatensatz.setVorlauf(a[4])
        tmpDatensatz.setRuecklauf(a[5])
        Datenliste.append(tmpDatensatz)         #anhängen an das Listenende und hier liegt glaub ich das Problem!!!
    return Datenliste
    

print 'Kontrolle'     
d = readDaten('missio4.csv')
print d
Zuletzt geändert von Anonymous am Freitag 26. August 2011, 19:49, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Bitte verwende hier im Forum die Tags für Python-Code, sonst kann man das Programm so schlecht lesen.

Grundsätzlich sieht das aus, als wäre es von einem frisch konvertierten Java-Entwickler geschrieben worden. Getter und Setter sind in Python eher unüblich. Die Verwendung von zwei Unterstrichen zu Beginn eines Variablennamens ist im Regelfall auch nicht erforderlich. Um einen Bezeichner als "privat" zu kennzeichnen genügt ein Unterstrich.

Die Art und Weise wie du die Datei ausliest ist zwar möglich, aber etwas umwegig. Statt alle Daten in eine Liste einzulesen und dann über die Liste zu iterieren kannst du das auch direkt machen.

Code: Alles auswählen

fp = open(filename, 'r')
for line in fp:
    # do something
close(fp)
Das kann man jetzt noch etwas schöner ausdrücken.

Code: Alles auswählen

with open(filename, 'r') as fp:
    for line in fp:
        # do something
In der Liste hast du aber auch bei deinem Code hinterher Datensatz-Objekte und genau das wird auch ausgegeben. Du könntest deinem Datensatz-Objekt eine __str__-Methode verpassen um die Inhalte bei einem einfachen print auszugeben.
BlackJack

@Mucku: Schau Dir auch mal das `csv`-Modul in der Standardbibliothek an. Und da insbesondere auch den `DictReader`.
Mucku
User
Beiträge: 7
Registriert: Mittwoch 17. August 2011, 22:37

Vielen Dank für die schnellen Antworten!
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Das ganze Programm könnte in Python 3 (Umlaute in den Bezeichnern) so aussehen:

Code: Alles auswählen

class Datensatz:
    def __init__(self, nummer, datum, zeit, idx, außen, vorlauf, rücklauf):
        self.nummer, self.datum, self.zeit, self.idx, self.außen, self.vorlauf, self.rücklauf \
            = nummer, datum, zeit, idx, außen, vorlauf, rücklauf

def anpassen(line):
    a = line.split(";")
    b = a[0].split()
    return b[:2] + a[1:]

def einlesen(name):
    with open(name) as f:
        return [Datensatz(*anpassen(line)) for line in f]
Getter und Setter sind unüblich (und werden missbilligt), Dateien muss man nicht komplett einlesen, um sie aufzuzählen, das umfummeln einer Zeile kann man auch ohne destruktive Operationen machen (die ich generell missbilligen würde) und die Comprehension vermeidet den Fehler im Original-Programm, wo ein Datensatz-Exemplar fälschlich immer wieder verwendet wird.

Und mit einem namedtuple wird das ganze noch mal kürzer:

Code: Alles auswählen

from collections import namedtuple

Datensatz = namedtuple("Datensatz", "nummer, datum, zeit, idx, außen, vorlauf, rücklauf")
Stefan
Mucku
User
Beiträge: 7
Registriert: Mittwoch 17. August 2011, 22:37

@sma
Vielen Dank! Aber irgendwie löst sich mein Problem nicht auf!
Ich bekomme immer noch folgende Fehlermeldung, wenn ich die Funktionen benutze:

[<__main__.Datensatz instance at 0x022B07D8>, <__main__.Datensatz instance at 0x022B0828>, <__main__.Datensatz instance at 0x022B0878>, <__main__.Datensatz instance at 0x022B08C8>, <__main__.Datensatz instance at 0x022B0918>]

was bedeutet das denn?
Was genau muss ich nach der Definition der Funktionen denn noch eingeben, um mir die eingelesen Daten anzeigen zu lassen?
Wie gesagt, die einzulesende datei ist eine 5x5 tabelle(erste Spalte enthält zwei Werte) als csv Datei abgespeichert.
Entschuldigt meine Unwissenheit, aber irgendwie verzweifel ich gerade daran :(
Danke Mucku
deets

Was ist denn daran genau der Fehler? Das ist das, was dein Programm macht - eine Liste von Datensatz-Objekten zu erzeugen. Einen Fehler sehe ich da nicht. Du kannst die Methoden __str__ und __repr__ ueberladen, damit dir die Ausgabe noch etwas anderes liefert (das ist wie toString bei Java) - aber das aendert nix an der Logik.
Mucku
User
Beiträge: 7
Registriert: Mittwoch 17. August 2011, 22:37

Ich möchte einfach die daten der tabelle anschließend angezeigt bekommen und dachte das sei so direkt möglich(evt mit print Anweisungen oder so).
Also ist das keine Fehlermeldung sondern das was in der Liste steht!?Ich möchte aber die einzelen Werte sehen!
Wie soll ich denn diese __str__ da einbauen?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Mucku hat geschrieben:Ich möchte einfach die daten der tabelle anschließend angezeigt bekommen und dachte das sei so direkt möglich(evt mit print Anweisungen oder so).
Also ist das keine Fehlermeldung sondern das was in der Liste steht!?Ich möchte aber die einzelen Werte sehen!
Wie soll ich denn diese __str__ da einbauen?
http://docs.python.org/reference/datamo ... ject.__str__

Die Frage ist aber, was du erwartest, was angezeigt werden soll. Gut, du möchtest, dass die von dir gewünschten Attribute des Datensatz-Objekts ausgegeben werden. Das kann das Programm aber nicht von selber wissen. Daher musst du entweder mittels __str__ oder __repr__ die Datensatz-Klasse so modellieren, dass die Daten bei einem Aufruf von print ausgegeben werden oder du holst dir die Daten von Hand.

In deinem Code hast du einen Bezeichner d, der eine Liste von Datensatzobjekten enthält. Jetzt brauchst du nur Folgendes:

Code: Alles auswählen

for entry in d:
    print entry.getNummer()
Mir macht nur noch ein wenig Sorge, dass du gar nicht auf die restlichen Kommentare zum Code eingegangen bist. Sicherheitshalber möchte ich dir hier noch mal folgenden Punkt ans Herz legen: Lass die Getter und Setter weg. Die ebenfalls erwähnten unnötigen doppelten Unterstriche verschwinden dann ja ebenfalls.


Noch mal Code zu __str__ und __repr__ als Ergänzung (Python 2.7):

Code: Alles auswählen

>>> class Name(object):
	def __init__(self, first_name, last_name):
		self.first = first_name
		self.last = last_name
	def __repr__(self):
		return '({0}, {1})'.format(self.first, self.last)
	def __str__(self):
		return 'Mein Name ist {1}. {0} {1}.'.format(self.first, self.last)

	
>>> agent = Name('James', 'Bond')
>>> print agent
Mein Name ist Bond. James Bond.
>>> agent
(James, Bond)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Mucku hat geschrieben:Ich möchte einfach die daten der tabelle anschließend angezeigt bekommen und dachte das sei so direkt möglich(evt mit print Anweisungen oder so).
Wenn du den Rat von sma beherzigt und namedtuple verwendet hättest, wärst du schon am Ziel:

Code: Alles auswählen

from collections import namedtuple

Datensatz = namedtuple("Datensatz", "nummer, datum, zeit, idx, außen, vorlauf, rücklauf")

ds = [Datensatz(12, '2011-08-29', '13:15', 456, 'Sonnenschein', 'vor', 'zurück')]
print(ds)
Ergebnis:

Code: Alles auswählen

[Datensatz(nummer=12, datum='2011-08-29', zeit='13:15', idx=456, außen='Sonnenschein', vorlauf='vor', rücklauf='zurück')]
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Mucku: Versuch's mal so:

Code: Alles auswählen

import csv

from collections import namedtuple

Datensatz = namedtuple("Datensatz", "nummer, datum, zeit, idx, außen, vorlauf, rücklauf")

def read_and_transform(filename, transform=lambda x:x):
    with open(filename, 'r') as csv_file:
        return [transform(each) for each in csv.reader(csv_file, delimiter=';')]

def transmogrify(record):
    return Datensatz(*(record[0].split()[:2] + record[1:]))

print read_and_transform('missio4.csv', transmogrify)
In specifications, Murphy's Law supersedes Ohm's.
arphex
User
Beiträge: 1
Registriert: Freitag 9. September 2011, 08:52

Hallo zusammen,

möchte erstmal alle begrüßen, da dies mein erster Post ist! :-)

Ich finde den Thread recht interessant.
Kurz zu mir und meinem Anwendungsfall:

Z.z. beschäftige ich mich mit modellgetriebener Testfallgenerierung.
In meinem Testfallgenerator (welcher mir aus meinem UML per XSLT Testfälle generiert), kann ich
per Python-Code den Ablauf steuern.

Seit ein paar Tagen nun suche ich nun auch eine Lösung
a) bestehende .csv-Dateien zu lesen
b) diese dann zu analysieren und zu ergängzn.

Dies habe ich bis jetzt über csv.writer sowie eine Transformation in sqlite3 und cursor() auf execute('Create etc') probiert.

Ohne zuriedenstellem Ergebnis.

Ich würde gerne den Ansatz mit den namedtuple testen, jedoch bekomme ich in
- python32 - shell
- Visual Studio 2010 mit python plugin und
- pyscripter immer:

TypeError: namedtuple() takes at most 4 positional arguments (12 given)

Code: Alles auswählen

set_typelist = namedtuple('TYPEFAMILY','TYPEINFO','TYPECODE','TESTNR','ADAPTER','CONTACTPOS','TESTPOS','BCMODE','ACTIVE','ECSTART','ECSTOP','IDLAYOUT')

def read_and_transform(filename, transform=lambda x:x):
    with open(filename, 'r') as csv_file:
        return [transform(each) for each in csv.reader(csv_file, delimiter=';')]

def transmogrify(record):
    return set_typelist(*(record[0].split() [2] + record[1:]))

print (read_and_transform('C:\TestCollection\Testing\CSV\test.csv', transmogrify))
Woran kann das denn liegen?

Viele Grüße
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

arphex hat geschrieben:Woran kann das denn liegen?
Daran, dass du namedtuple() falsch verwendest. Die Feldnamen bilden eins der vier Argumente, die für `namedtuple()` maximal möglich sind. Setze deine Namen einfach in eine Liste und übergib diese Liste als zweites Argument. Das erste Argument sollte der zu verwendende Name für das Named Tuple sein. Die Doku habe ich verlinkt.
Antworten