wieso ist wirte in Klassen so?

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
ll9
User
Beiträge: 34
Registriert: Samstag 9. Februar 2013, 15:13

Hallo,

die Frage ist vielleicht etwas komisch formuliert, lasst sie mich mal an diesen beispielcode erläutern.

Code: Alles auswählen

class Test(object):
    
    def __init__(self, letter, length):
        self.letter = letter
        self.length = length
        
    def write_sth(self):
        self.offen = open('test.txt', 'w')
        self.offen.write(self.letter * self.length)
        
x = Test('x', 4)
y = Test('y', 10)

x.write_sth()
y.write_sth()
raw_input()
Hier noch, was jetzt in test.txt steht.
xxxxyyyyyy

Ich will ja eigentlich, dass nach den 4 x die 10 y kommen, die Klasse Test schreibt jedoch scheinbar nur etwas an die exakt selbe Position und überschreibt fals schon Schrift vorhanden ist scheinbar auch nichts. Was müsste ich denn genau ändern, damit er es so schreibt?
xxxx
yyyyyyyyyy
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo,

dein Programm hat einige Probleme.

1. Du öffnest die Datei zwar, schließt sie aber nicht. Das ist ganz wichtig. Es ist wesentlich besser, das so zu schreiben:

Code: Alles auswählen

with open("test.txt", "w") as datei:
    datei.write("hallo")
Dann wird die Datei auf jeden Fall geschlossen, wenn du den Block verlässt. Dateien sollte man immer mit diesem with ... as ... öffnen.

2. Du öffnest als 'w'. Das überschreibt aber doch das was du vorher gespeichert hast. Schau mal hier (http://docs.python.org/3.3/library/functions.html#open), dort steht was von 'a' für append, also anhängen.


Ich habe deinen Code jetzt mal so umgeschrieben, so funktioniert er, wie du es haben willst:

Code: Alles auswählen

class Test(object):
   
    def __init__(self, letter, length):
        self.letter = letter
        self.length = length
       
    def write_sth(self):
        with open("test.txt", "a") as datei:
            datei.write(self.letter * self.length + "\n")

x = Test('x', 4)
y = Test('y', 10)
 
x.write_sth()
y.write_sth()
Allerdings möchte ich anmerken, dass ich hier den Sinn der Klasse nicht wirklich erkennen kann. Bzw die Klasse wirkt etwas unlogisch und ich weiß nicht, wieso du hier unbedingt eine Klasse verwendest.
Zuletzt geändert von Hellstorm am Samstag 7. Dezember 2013, 16:24, insgesamt 2-mal geändert.
ll9
User
Beiträge: 34
Registriert: Samstag 9. Februar 2013, 15:13

Danke für deine Antwort.
Allerdings möchte ich anmerken, dass ich hier den Sinn der Klasse nicht wirklich erkennen kann. Bzw die Klasse wirkt etwas unlogisch und ich weiß nicht, wieso du hier unbedingt eine Klasse verwendest.
Mir ist durchaus bewusst, dass diese Klasse in diesen Fall sinnlos ist, war auch nur zum Verständnis da.

Also mit diesem with open... as schließt sich die Datei von selbst wieder? Gut zu wissen. Ich frag mich dann nurnoch, ab wann sich diese Datei wieder schließt. Ist die sofort nach der Einrückung wieder geschlossen?

Das 'w' überschreibt weiß ich auch, jedoch ist es doch komisch dass dann statt 'yyyyyyyyyy' bloß 'xxxxyyyyyy' steht. Normalerweise sollte dann ja nur 'yyyyyyyyyy' da stehen oder?

Wenn ich statt 'w' 'a' schreibe, hab ich das Problem, dass ich, wenn ich das Programm öfters ausführe er mir mehrmals die selben Zeilen hinschreibt. Ich will aber, dass er jedes mal, wenn ich das Programm starte, dass das Textdokument zuerst gelöscht wird und dann eben wieder diese 2 Zeilen geschrieben werden. Gibt es dafür eine Lösung? Ich hab mal irgendwo gelesen, dass man glaube ich Die 'Read' und 'Write' Variablen in open kombinieren kann, in etwa so: open('test.text', 'rw') Bin mir nicht sicher, ob's wirklich 'rw' war. Kann man sowas dann vielleicht auch mit 'Write' und 'append' machen als ein 'aw'? Hoffe, ihr versteht was ich meine.

EDIT: Hab grad festgestellt, dass mein 'rw' in wirklichkeit 'w+' oder auch 'r+' ist. So was wie 'a+' gibt's zwar, aber nicht so wie ich's gerne hätte.
BlackJack

@ll9: Wenn Du die Datei am Programmanfang gelöscht haben willst, dann lösche sie doch einfach am Programmanfang. :-)

Das ganze klingt trotzdem immer noch eigenartig. Was genau versuchst Du denn da zu machen? Eine Datei zum lesen und schreiben öffnen würde ich bei einer Textdatei nicht empfehlen. Das macht eigentlich nur bei Binärdateien Sinn wo bestimmte Informationen an festen Positionen in der Datei stehen.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Von dem Edit von oben in eine neue Antwort kopiert:
Ich sehe hier vor allem als Problem, dass du mehrere Objekte erstellst, die allerdings alle im Endeffekt auf die gleiche Datei zugreifen. Das ist doch ziemlich unlogisch. Wenn ich hier mit Klassen arbeiten würde, würde ich je ein Objekt für eine Datei verwenden, d.h. dass z.B. x auf die Datei „test.txt“ zugreift und y auf „hallo.txt“. Außerdem würde ich es umgekehrt machen, dass du den Dateinamen an __init__() übergibst und so das Dateiobjekt öffnest. An die Funktion write_sth() würde ich dann den Text, den du speichern möchtest, übergeben.

So würdest du also zuerst eine Datei öffnen, indem du das Objekt erstellst. Danach kannst du so lange etwas hineinschreiben, wie du möchtest. Anschließend müsstest du allerdings die Datei manuell wieder schließen.
Im Grunde wäre das aber nichts anderes als das, was die open()-Funktion schon macht. Das einzige, was dein Programm hier besonders macht ist das multiplizieren der Buchstaben, aber das würde ich doch eher in einer einfachen Funktion verwenden:

Code: Alles auswählen

def multipliziere_buchstabe(buchstabe, faktor):
	return buchstabe * faktor + "\n"
	
with open("test.txt", "w") as datei:
	datei.write(multipliziere_buchstabe("x", 4))
	datei.write(multipliziere_buchstabe("y", 10))
So hätte ich dein Programm gemacht. Als Ergebnis bekommt man dann:

Code: Alles auswählen

xxxx
yyyyyyyyyy


Neuer Text:
Ja, damit schließt sich die Datei wieder wenn man den Block (also die Einrückung) verlassen hat. Ist immer sinnvoll. So genau weiß ich das auch nicht, aber ich würde es als sinnvoll sehen, erst einmal die Daten aufzubereiten und anschließend kurz in die Datei zu speichern. Aber das sollte eher jemand fachkundigeres sagen.

Hm, naja, aber auch zum Üben fand ich die Klasse etwas falsch gedacht, also schon vom Konzept her. Aber so wirklich gut bin ich da auch nicht drin :D

Zum „w“: Naja, da steht truncating. Ehrlich gesagt weiß ich aber auch nicht genau, was das jetzt heißt, wird aber wohl genau der Effekt sein, den du meinst. Bzw. das kann auch an dem fehlenden Schließen der Datei liegen.

Zu deinem letzten Absatz: Naja, das Problem ist, dass du die Datei bei jedem Schreibversuch neu öffnest (und sie vorher nicht schließt!). Entweder sammelst du die Sachen erst und schreibst sie dann alle auf einmal, oder du öffnest die Datei, schreibst alles nacheinander hinein und schließt sie dann ordnungsgemäß wieder (und dann ist das Programm beendet).
Benutzeravatar
pillmuncher
User
Beiträge: 1528
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Hellstorm hat geschrieben:Zum „w“: Naja, da steht truncating. Ehrlich gesagt weiß ich aber auch nicht genau, was das jetzt heißt, [...]
guckstu hier: http://dict.leo.org/#/search=truncating
In specifications, Murphy's Law supersedes Ohm's.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

pillmuncher hat geschrieben:
Hellstorm hat geschrieben:Zum „w“: Naja, da steht truncating. Ehrlich gesagt weiß ich aber auch nicht genau, was das jetzt heißt, [...]
guckstu hier: http://dict.leo.org/#/search=truncating
Hab ich ;) Konnte aber nicht genau verknüpfen was genau an der Datei jetzt abgeschnitten wird. Der vordere Teil? Hinten? Oder wie genau?
BlackJack

@Hellstorm: `file`-Objekte haben eine `truncate()`-Methode. Und die macht das gleiche wie die C-Funktion `truncate()` die POSIX-Standard ist. Und das Linux-Programm ``tuncate`` benutzt die Funktion um das dem Benutzer auf der Konsole zur Verfügung zu stellen.
ll9
User
Beiträge: 34
Registriert: Samstag 9. Februar 2013, 15:13

@ll9: Wenn Du die Datei am Programmanfang gelöscht haben willst, dann lösche sie doch einfach am Programmanfang. :-)

Das ganze klingt trotzdem immer noch eigenartig. Was genau versuchst Du denn da zu machen? Eine Datei zum lesen und schreiben öffnen würde ich bei einer Textdatei nicht empfehlen. Das macht eigentlich nur bei Binärdateien Sinn wo bestimmte Informationen an festen Positionen in der Datei stehen.
Das mit dem am Anfang löschen hab ich auch schon in betracht gezogen, wollte das aber eher automatisierter, also in der Klasse drin haben. Werde ich aber denke ich mal so machen.

Wie bereits gesagt, das Programm war nur zum veranschaulichen da und hat mir meinen eigenen Programm nicht so viel zu tun. Ich kann aber natürlich erklären, was es mit meinen Programm auf sich hat. Mein Programm ist so ein Vokabel-abfrag Programm. Ich arbeite auch schon länger daran. Damals habe ich leider von Pickle noch nichts gehört und die Vokabeln speichern sich ja nicht von selbst ab, deswegen hab ich das selber manuell auf ein Textdokument gespeichert. Nicht gerade eine gute Lösung, ich weiß, ich will mir Pickle sobald ich mit dem Programm fertig bin auch anschauen, aber zumindest für dieses Programm würde ich gerne noch so weiter machen.
Ich führe das Programm also einmal aus, um deutsche Vokabeln abzuspeichern und ein zweites mal um die englischen einzutippen und abzuspeichern.
dass du den Dateinamen an __init__() übergibst und so das Dateiobjekt öffnest. An die Funktion write_sth() würde ich dann den Text, den du speichern möchtest, übergeben.
Das versteh ich leider auf Anhieb nicht so ganz, kannst du mir vielleicht ein beispiel dazu nennen?
BlackJack

@ll9: Aber wie schreibst Du dass denn dann in die Datei? Das klingt jetzt *noch* komischer.

`pickle` würde ich dafür nicht nehmen. Das ist Python-spezifisch. Ein allgemeinerer Standard wie JSON wäre da IMHO besser. Oder vielleicht sogar irgendein Format dass es für Vokabeln schon gibt.

Letztlich läuft aber selbst `pickle` darauf hinaus das Du die Daten komplett im Speicher hältst und *komplett* in eine Datei schreibst. Eine Datei um eine neue Datei erweitern wäre dann Datei lesen, Vokabel im Speicher hinzufügen, Datei komplett neu schreiben. Damit würde sich Dein jetziges Problem gar nicht erst stellen.
ll9
User
Beiträge: 34
Registriert: Samstag 9. Februar 2013, 15:13

Letztlich läuft aber selbst `pickle` darauf hinaus das Du die Daten komplett im Speicher hältst und *komplett* in eine Datei schreibst. Eine Datei um eine neue Datei erweitern wäre dann Datei lesen, Vokabel im Speicher hinzufügen, Datei komplett neu schreiben. Damit würde sich Dein jetziges Problem gar nicht erst stellen.
Ich weiß grad nicht was ich da so recht anders mache.
Ich würde es z.b so in ein textdokument schreiben lassen:

Code: Alles auswählen

deutsch = [deutschvokabeln]
englisch = [englischvokabel]
dann würde ich halt 'deutsch' und 'englisch' importieren lassen und wieder vokabeln hinzufügen und dass dann wieder speichern. Was mache ich denn dann nicht so *komplett* ?
BlackJack

@ll9: Na offenbar öffnest Du die Datei an zwei verschiedenen Stellen im Programm um jeweils eine Sprache zu schreiben. Statt einmal zu öffnen und alle Sprachen zu schreiben.

An der ”Struktur” fehlt jetzt auch irgendwo die Struktur, denn die Vokabeln mit der gleichen Bedeutung aber in verschiedenen Sprachen gehören ja *zusammen*, darum sollte man die auch nicht in „parallelen” Listen speichern. Ich nehme mal an das ist auch grundsätzlich ein Problem in Deinem Programm.
Antworten