Problem mit "file"

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
Anfänger1911
User
Beiträge: 62
Registriert: Donnerstag 17. November 2005, 16:25

Ich habe versucht ein kleines Highscoreprogramm zuschreiben. Dieses Programm soll aus einem file die Highscoredaten auslesen und sie auch in diesem file speichern. Die Funktionen zum Higscoreauslesen und Highscorespeichern in meinem Programm sehen so aus:

Code: Alles auswählen

punkte=0

def ende(self):
        global highscore, daten, platz1, platz2, platz3, platz4, platz5, platz6, platz7, platz8, platz9, platz10, pktplatz1, pktplatz2, pktplatz3
        global pktplatz4, pktplatz5, pktplatz6, pktplatz7, pktplatz8, pktplatz9, pktplatz10, punkte
        self.highscorelesen()
        punkte=int(punkte)
        pktplatz1=int(pktplatz1)
        pktplatz2=int(pktplatz2)
        pktplatz3=int(pktplatz3)
        pktplatz4=int(pktplatz4)
        pktplatz5=int(pktplatz5)
        pktplatz6=int(pktplatz6)
        pktplatz7=int(pktplatz7)
        pktplatz8=int(pktplatz8)
        pktplatz9=int(pktplatz9)
        pktplatz10=int(pktplatz10)
        if (punkte >= pktplatz1 or punkte >= pktplatz2 or punkte >= pktplatz3 or punkte >= pktplatz4 or punkte >= pktplatz5 or punkte >= pktplatz6
        or punkte >= pktplatz7 or punkte >= pktplatz8 or punkte >= pktplatz9 or punkte >= pktplatz10):
            self.neuerrekord()
        else:
            self.beenden()

def neuerrekord(self):
        self.rekordfenster=Tk()
        self.neuerrekord=Label(self.rekordfenster, font=('Arial', 16, 'bold'), bg='#FF9900', fg='#FF0000', text='Neuer Rekord!')
        self.namenlabel=Label(self.rekordfenster, height=5, bg='#FF9900')
        self.namenlabel2=Label(self.namenlabel, font=('Arial', 10), bg='#FF9900', width=25, text='Geben Sie Ihren Namen ein:')
        self.nameneingabe=Entry(self.namenlabel, width=15, bg='black', fg='yellow')
        self.okbutton= Button(self.rekordfenster, font=('Arial', 10, 'bold'), text='OK', command=self.highscorespeichern, width=5, height=1, bg='#000000', fg='yellow')
        self.neuerrekord.pack(pady=10, padx=10)
        self.namenlabel.pack(pady=5, padx=5)
        self.namenlabel2.pack(pady=5, padx=5)
        self.nameneingabe.pack(pady=5, padx=5)
        self.okbutton.pack(pady=10)
        self.rekordfenster.mainloop()

def highscorelesen(self):
        global highscore, platz1, platz2, platz3, platz4, platz5, platz6, platz7, platz8, platz9, platz10, pktplatz1, pktplatz2, pktplatz3
        global pktplatz4, pktplatz5, pktplatz6, pktplatz7, pktplatz8, pktplatz9, pktplatz10
        try:
            daten=file('Dateipfad\highscore.txt', 'r')  
            highscore=daten.readlines()
            platz1=highscore[0]
            pktplatz1=highscore[1]
            platz2=highscore[2]
            pktplatz2=highscore[3]
            platz3=highscore[4]
            pktplatz3=highscore[5]
            platz4=highscore[6]
            pktplatz4=highscore[7]
            platz5=highscore[8]
            pktplatz5=highscore[9]
            platz6=highscore[10]
            pktplatz6=highscore[11]
            platz7=highscore[12]
            pktplatz7=highscore[13]
            platz8=highscore[14]
            pktplatz8=highscore[15]
            platz9=highscore[16]
            pktplatz9=highscore[17]
            platz10=highscore[18]
            pktplatz10=highscore[19]
            daten.close()
        except:
            self.fehler()

def highscorespeichern(self):
        global platz1, platz2, platz3, platz4, platz5, platz6, platz7, platz8, platz9, platz10, pktplatz1, pktplatz2, pktplatz3, pktplatz4, pktplatz5, pktplatz6, pktplatz7, pktplatz8, pktplatz9, pktplatz10, punkte
        if punkte > pktplatz1:
            pktplatz1 = str(punkte)
            platz1 = self.nameneingabe.get()
        elif punkte == pktplatz1 or punkte > pktplatz2:
            pktplatz2 = str(punkte)
            platz2 = self.nameneingabe.get()
        elif punkte == pktplatz2 or punkte > pktplatz3:
            pktplatz3 = str(punkte)
            platz3 = self.nameneingabe.get()
        elif punkte == pktplatz3 or punkte > pktplatz4:
            pktplatz4 = str(punkte)
            platz4 = self.nameneingabe.get()
        elif punkte == pktplatz4 or punkte > pktplatz5:
            pktplatz5 = str(punkte)
            platz5 = self.nameneingabe.get()
        elif punkte == pktplatz5 or punkte > pktplatz6:
            pktplatz6 = str(punkte)
            platz6 = self.nameneingabe.get()
        elif punkte == pktplatz6 or punkte > pktplatz7:
            pktplatz7 = str(punkte)
            platz7 = self.nameneingabe.get()
        elif punkte == pktplatz7 or punkte > pktplatz8:
            pktplatz8 = str(punkte)
            platz8 = self.nameneingabe.get()
        elif punkte == pktplatz8 or punkte > pktplatz9:
            pktplatz9 = str(punkte)
            platz9 = self.nameneingabe.get()
        elif punkte == pktplatz9 or punkte > pktplatz10:
            pktplatz10 = str(punkte)
            platz10 = self.nameneingabe.get()
            
        try:
            daten2=file('Dateipfad\highscore.txt', 'w')
            daten2.write(platz1,pktplatz1,'\n',platz2,pktplatz2,'\n',platz3,pktplatz3,'\n',platz4,pktplatz4,'\n',
                         platz5,pktplatz5,'\n',platz6,pktplatz6,'\n',platz7,pktplatz7,'\n',platz8,pktplatz8,'\n',
                         platz9,pktplatz9,'\n',platz10,pktplatz10)
            daten2.close()
        except:
            self.fehler()
Das Auslesen scheint auch zu funktionieren allerdings schreibt mein Programm nichts in die Datei. Ich sehe hier aber keinen Fehler. Bitte helft mir! Vielen Dank im Vorraus.

MfG
Anfänger
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

http://www.python.org/dev/peps/pep-0008/
[wiki]Lange Zeilen im Sourcecode[/wiki]

lg
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

EDIT:

Entferne mal try und except und schau mal was passiert.

Code: Alles auswählen

try:
            daten2=file('Dateipfad\highscore.txt', 'w')
            daten2.write(platz1,pktplatz1,'\n',platz2,pktplatz2,'\n',platz3,pktplatz3,'\n',platz4,pktplatz4,'\n',
                         platz5,pktplatz5,'\n',platz6,pktplatz6,'\n',platz7,pktplatz7,'\n',platz8,pktplatz8,'\n',
                         platz9,pktplatz9,'\n',platz10,pktplatz10)
            daten2.close()
        except:
            self.fehler()

Noch ein Tipp: Nie einen leeres except schreiben um alles aufzufangen sondern fange die Exception direkt auf...

Code: Alles auswählen

IOError: [Errno 2] No such file or directory: 'Dateipfad\\highscore.txt'
...in dem Beispiel: ->

Code: Alles auswählen

except IOError:
    [...]
lg
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Anfänger1911 hat geschrieben:

Code: Alles auswählen

def highscorelesen(self):
        global highscore, platz1, platz2, platz3, platz4, platz5, platz6, platz7, platz8, platz9, platz10, pktplatz1, pktplatz2, pktplatz3
        global pktplatz4, pktplatz5, pktplatz6, pktplatz7, pktplatz8, pktplatz9, pktplatz10
        try:
            daten=file('Dateipfad\highscore.txt', 'r')  
            highscore=daten.readlines()
            platz1=highscore[0]
            pktplatz1=highscore[1]
            platz2=highscore[2]
            pktplatz2=highscore[3]
            platz3=highscore[4]
            pktplatz3=highscore[5]
            platz4=highscore[6]
            pktplatz4=highscore[7]
            platz5=highscore[8]
            pktplatz5=highscore[9]
            platz6=highscore[10]
            pktplatz6=highscore[11]
            platz7=highscore[12]
            pktplatz7=highscore[13]
            platz8=highscore[14]
            pktplatz8=highscore[15]
            platz9=highscore[16]
            pktplatz9=highscore[17]
            platz10=highscore[18]
            pktplatz10=highscore[19]
            daten.close()
        except:
            self.fehler()
Hallo Anfänger!

Ich habe mir nicht alles angesehen und weiß nicht warum dein Programm nicht funktioniert, aber es wundert mich zumindest nicht. :roll:

Hier habe ich ein paar Verbesserungsvorschläge und ein wenig Kritik.

- Du hast mehr Chancen auf Hilfe, wenn du uns ein "lauffähiges" Stück Code zeigst, das dein Problem demonstriert. Dass dieser von dir gezeigter Code aus einer Klasse kommt, ist nur klar, weil überall die "self." herumschwirren. Was sonst noch mit diesen Variablen passiert kann man nur erahnen.

- Du verwendest so viele globale Variablen, dass mir schon Angst und Bange wird. Globale Variablen sollten nur dann eingesetzt werden, wenn alles andere viel komplizierter und schwieriger zu durchschauen ist.

- Immer dann, wenn du mehrere Variablenamen mit einer laufenden Nummerierung im Namen hast ("platz1", "platz2",...), dann solltest du darüber nachdenken, ob du nicht lieber auf eine Liste zurückgreifen möchtest. (``plaetze[0] = x; plaetze[1] = y``) Damit würdest du dir bei sich wiederholenden Aufgaben einfacher tun. Z.B.:

Code: Alles auswählen

for index, item in enumerate(plaetze):
    plaetze[index] = int(item)
- ``'Dateipfad\highscore.txt'``: Verwende lieber einen Slash (/) statt dem Backslash (\), da dir der Backslash normalerweise Zeichen "escaped". Noch besser wäre, wenn du die dafür vorgesehene Funktion verwendest. -->

Code: Alles auswählen

>>> os.path.join("dateipfad", "highscore.txt")
'dateipfad\\highscore.txt'
>>>
Damit wärst du dann komplett plattformunabhängig unterwegs.

- Und hier noch ein Beispiel:

Code: Alles auswählen

try:
    f = file(os.path.join("dateipfad", "highscore.txt"), 'rU')
    try:
        for i in range(1, 10 + 1):
            # plaetze
            line = f.readline()
            if line:
                plaetze[i] = line.rstrip()
            else:
                plaetze[i] = None
            # pktplaetze
            line = f.readline()
            if line:
                pktplaetze[i] = line.rstrip()
            else:
                pktplaetze[i] = None
    finally:
        f.close()
except IOError:
    for i in range(1, 10 + 1):
        plaetze[i] = None
        pktplaetze[i] = None
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Anfänger1911
User
Beiträge: 62
Registriert: Donnerstag 17. November 2005, 16:25

Hi!
- Du verwendest so viele globale Variablen, dass mir schon Angst und Bange wird. Globale Variablen sollten nur dann eingesetzt werden, wenn alles andere viel komplizierter und schwieriger zu durchschauen ist.
Soweit ich weiß sind Globale Varaiablen doch dazu da, damit die Variablen im ganzen Programm immer gleich bleiben und man sie nicht in jede Definition neu reinschreiben muss, oda ist das falsch?
Damit wärst du dann komplett plattformunabhängig unterwegs.
Ich habe vor mein Programm später mit py2exe zu complimieren (oda wie das auch imma heißt). Läuft das Programm dann nicht sowieso nur unter Windows wenn ich es unter Windows complimiere?

Vielen Dank für die Hilfe! Ich muss mir das alles nochmal ganz genau angucken und melde mich dann wieder wenn ich mein Programm ein wenig verändert habe.

MfG
Anfänger
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi!

So könnte z.B. eine HighScore-Klasse aussehen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import os
import pickle
from StringIO import StringIO
import datetime


class Score(object):
    """
    Diese Klasse entspricht einem Punktestand.
    """
    
    def __init__(self, score, timestamp, name):
        """
        Initialisiert den Score
        """
        
        self.score = int(score)
        self.timestamp = timestamp
        self.name = name
    
    
    def __cmp__(self, other_score):
        """
        Vergleiche werden nicht nur auf den Score, sondern auf den
        Timestamp durchgeführt. Wenn punktgleich, dann steht der ältere
        Score weiter oben.
        """
        
        # Score vergleichen
        cmp_score = cmp(self.score, other_score.score)
        if cmp_score <> 0:
            return cmp_score
        else:
            # Punktegleichstand. Der älter Score gilt als höher
            return cmp(other_score.timestamp, self.timestamp)
    
    
    def __str__(self):
        """
        Gibt den Score als Textzeile (ohne Timestamp) zurück
        """
        
        return "%10i  %s" % (self.score, self.name)


class HighScore(object):
    """
    Diese Klasse enthält alle Scores
    """
    
    def __init__(self, max_scores = 10):
        """
        Initialisiert den Highscore
        """
        
        self.scores = []
        self.max_scores = max_scores
    
    
    def load_scorefile(self, filename):
        """
        Läd die Scores aus der angegebenen Datei. Wenn diese noch nicht
        exisitert, dann wird nichts gemacht.
        """
        
        try:
            f = file(filename, "rb")
            try:
                self.scores = pickle.load(f)
            finally:
                f.close()
        except IOError:
            pass
    
    
    def save_scorefile(self, filename):
        """
        Speichert die Scores in die angegebene Datei.
        """
        f = file(filename, "wb")
        try:
            pickle.dump(self.scores, f, protocol = pickle.HIGHEST_PROTOCOL)
        finally:
            f.close()
    
    
    def add_score(self, score):
        """
        Fügt den Score der Liste hinzu. Danach wird die Liste absteigend nach
        Punkten und Timestamp sortiert. Nach dem Sortieren wird die Liste auf
        self.max_scores gekürzt.
        """
        
        self.scores.append(score)
        self.scores.sort(reverse = True)
        
        if len(self.scores) > 10:
            for i in range(len(self.scores) - 1, self.max_scores - 1, -1):
                del self.scores[i]
    
    
    def get_scores(self):
        """
        Gibt die Liste mit den Scores zurück
        """
        
        return self.scores
    
    
    def __str__(self):
        """
        Gibt die Scores als Anzeigetext zurück
        """
        
        ret = StringIO()
        
        ret.write(("-" * 70) + "\n")
        ret.write("     Score  Name\n")
        ret.write(("-" * 70) + "\n")
        for score in self.scores:
            ret.write(str(score) + "\n")
        ret.write(("-" * 70) + "\n")
        ret.write("\n")
        
        return ret.getvalue()

    
def main():
    """
    Testen
    """
    
    import time
    TESTFILENAME = "test_highscore.bin"
    
    
    hs1 = HighScore()
    
    s = Score(1005, datetime.datetime.now(), "Halvar der Schreckliche")
    hs1.add_score(s)

    s = Score(2000, datetime.datetime.now(), "Nudlaug Thompson")
    hs1.add_score(s)

    s = Score(500, datetime.datetime.now(), "Das Finanzampt")
    hs1.add_score(s)
    
    time.sleep(1)
    
    s = Score(2000, datetime.datetime.now(), "Der Manastarke")
    hs1.add_score(s)
    
    print hs1
    hs1.save_scorefile(TESTFILENAME)
    del hs1
    
    hs2 = HighScore()
    hs2.load_scorefile(TESTFILENAME)
    
    print hs2
    
    os.remove(TESTFILENAME)


if __name__ == "__main__":
    main()
mfg
Gerold
:-)

Edit: Sortierung war verdreht
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Anfänger1911 hat geschrieben:Soweit ich weiß sind Globale Varaiablen doch dazu da, damit die Variablen im ganzen Programm immer gleich bleiben und man sie nicht in jede Definition neu reinschreiben muss, oda ist das falsch?
Hallo Anfänger!

Natürlich! Genau dafür sind sie da. Aber sie haben auch einen negativen Aspekt. Sie verhindern die klare Trennung von Codeteilen (Funktionen, Klassen). Wenn eine Funktion eine globale Variable zum Funktionieren benötigt, dann kann diese Funktion nicht mehr vom Rest des Codes abgetrennt werden.

Deshalb sollte man (wenn möglich) alle Daten, die eine Funktion zum Arbeiten braucht, an diese Funktion als Argumente übergeben. Genau so wie die Daten rein kommen, genau so sollten diese aus der Funktion auch wieder raus kommen. Klar erkennbar, mit ``return``.

Damit lassen sich einzelne Codeteile (Funktionen, Klassen) unabhängig testen und der Quellcode bleibt in überschaubare, einfach Codestücke aufgeteilt.

Code: Alles auswählen

ergebnis1, ergebnis2 = funktion(argument1, argument2)
Stell dir vor, du verwendest viele globale Variablen. Früher oder später wird eine globale Variable von mehreren Funktionen verändert. Es lässt sich dann kaum mehr nachvollziehen, wann die globale Variable welchen Wert hat.

Das sind auch die Gründe, weshalb man Geschäftslogik und Datenhaltung vom GUI-Code trennen sollte. Es macht keinen Sinn, die Highscore-Verwaltung in einer TkInter-Klasse vorzunehmen. So kann man die Highscore-Verwaltung nicht mehr testen lassen. Sobald eine GUI im Spiel ist, erschwert sich das Testen enorm. Das und viele weitere Gründe, die ich jetzt nicht aufzählen möchte, sprechen für viele kleine, unabhängige Codeabschnitte, die man als Programmierer wie bei einem Legospiel zu einem Programm zusammensetzen kann.

Doch! Einen Grund möchte ich noch aufzeigen. Irgendwann kommst du z.B. drauf, dass etwas zu viel Rechenleistung braucht. Hast du kleine Programmteile geschaffen, dann brauchst du dich beim Optimieren nur auf einen Codeabschnitt konzentrieren. Diesen kannst du dann testen und optimieren, ohne dass du irgendwelche Nebenwirkungen für die GUI befürchten musst. Du hast ja keine globalen Variablen verändert...

mfg
Gerold
:-)

PS: Globale Variablen haben natürlich auch ihre Daseinsberechtigung. Aber man sollte sie nicht so oft in so wenig Code einsetzen, wie du es gemacht hast. Und wenn schon, dann sollten die globalen Variablen -- meiner Meinung nach -- auch als solche erkennbar sein. (z.B. so: ``global_objektname``)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Anfänger1911 hat geschrieben:
Damit wärst du dann komplett plattformunabhängig unterwegs.
Ich habe vor mein Programm später mit py2exe zu complimieren (oda wie das auch imma heißt). Läuft das Programm dann nicht sowieso nur unter Windows wenn ich es unter Windows complimiere?
Hallo Anfänger!

Dein Programm läuft überall, wo auch Python läuft. Außer du verwendest Module oder Funktionen, die es nur für Windows gibt.

Was gibt es für einen Grund, nur für Windows zu programmieren, wenn man mit kaum merkbarem Mehraufwand ein Programm schreiben kann, dass auch unter Linux, Unix, Mac, usw. laufen könnte? :K

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten