Problem bei der for-Schleife

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
kleiner.epsilon
User
Beiträge: 25
Registriert: Sonntag 31. Oktober 2010, 14:31

Hallo,

hier eine kurze Zusammenfassung meines Programms:
Es beginnt mit einer Abfrage an den Benutzer, wieviele Durchläufe es machen soll. Die Eingabe ist der stop-Wert in range in der folgenden Schleife: Zufallszahlen werden erzeugt, die in einer Datei gespeichert werden, diese Datei wird mit einem anderen Programm geöffnet und ausgeführt (Parameterschätzung), dies ergibt 4 Parameter, die dann wieder eingelesen werden und in einer anderen Datei ausgegeben werden. Nach jedem Durchlauf müssen andere Parameter rauskommen und natürlich auch andere Zufallszahlen. (Innerhalb dieser Beschreibung kommen noch einmal 2 kleine for-Schleifen vor.)

Wenn ich diese große Schleife nur einmal durchlaufen lasse, und dies "von Hand" mehrmals wiederhole, kein Problem, alles funktioniert, es kommen unterschiedliche Parameter raus und die Zufallszahlen sind natürlich auch verschieden.

Wenn ich allerdings automatisch mehrmals durchlaufen lasse, zB. 5 mal, kommen 5 mal die gleichen Werte heraus, selbst die Zufallszahlen sind gleich (was nun wirklich nicht sein kann).

Mein erster Gedanke war, dass das Programm irgendwo zu schnell ist und schon Daten kopiert oder einliest noch bevor die Schleife zu Ende ist und die alten Daten überschrieben oder so.
Also habe ich den Befehl time.sleep() an verschiedenen Stellen eingebaut und damit rumgespielt und auch mal 5 sec warten lassen, was nun wirklich lange ist, hat aber nichts geholfen.

Was könnte ich noch ausprobieren?
Wo könnte der Fehler liegen?

Ich hoffe, ich habe den Code und mein Problem gut genug beschrieben, ansonsten kann ich noch mehr erklären.

Ich verstehe vorallem nicht, warum es funktioniert bei einen einzelnen Durchlauf mehrmals hintereinander, aber nicht bei mehreren. :K


Vielen Dank, Grüße.
deets

Wenn du ein Problem mit deinem Auto hast, was machst du dann? Nimmst du ein Taxi in die naechstbeste Werkstatt, erzaehlst dem Mechaniker dort ausfuehrlich und in blumigen Worten, wie es aussieht, was es macht und nicht macht, und hoffst dann, das er das diagnostizieren und womoeglich reparieren kann? Wohl kaum.

Insofern: tolle Code-Beschreibung deinerseits, aber wir muessten dann schon den Code sehen, damit wir da den Fehler finden koennen....
kleiner.epsilon
User
Beiträge: 25
Registriert: Sonntag 31. Oktober 2010, 14:31

:oops:

Code: Alles auswählen

an = input("Wie viele Durchlaeufe? ")
for lfd in range(0,an,1):
	try:	# hier werden die Zufallszahlen erzeugt
		eps= 0.8
		mu = 1	# mean
		sigma = 0.4	# standard deviation
		zp1 = gauss(mu,sigma) # zp2 ... zp5
	except:
		print 'Fehler beim Erzeugen der Zufallszahl'
	try:
		f1 = Popen( vplaninmyz, stdout=PIPE, shell=True).stdout
		subprocess.call( vplaninmyz, shell=True)
		ausgabe = open( vplaninausgabemyz, 'w+')
		for f in f1:
			ausgabe.write(str(f))
		ausgabe.close()
		f1.close()
	except:
		print 'Fehler bei Parameterschaetzung bzw. "vplaninausgabemyz".'
	try:	# hier werden die regulaeren Ausdruecke definiert
		re1 = compile('No corrector convergence', I)
		#re2 .... re11
		f2 = open( vplaninausgabemyz )
		text = f2.read()
		listesuch2 =  re5, re6, re7, re8, re9
		data2 =[]
		for re in listesuch2:
			m = re.search(text, 1500)
			n = m.group()
			p = n.split()
			par = p[1]
			data2.extend([par])
		f2.close()
	except:
		print 'Keine Suche in Datei "vplaninausgabemyz" '
	try:
		datendatei = open( pardateineu, 'a')
		for p in data2:
			datendatei.write("  %.7f"%(string.atof(p),))
		datendatei.write("  %5d  %.1f  %.1f  %10s  %25s  "%(lfd, eps, sigma, residual, lsqu))	
		for q in zufallszahlen:
			datendatei.write("%.12f "%(string.atof(q),))
		datendatei.write("\n")
		datendatei.close()
	except:
		print 'Kann Parameterliste nicht in "pardateineu.txt" speichern'
Habe versucht den Code soweit zu kürzen, dass er aber noch verständlich bleibt. Alle for-Schleifen sind noch drinnen und das Popen.

Wie gesagt, verstehe ich nicht, warum es bei einem Durchlauf funktioniert, aber bei mehreren es nur einmal funktioniert und er dann immer diese Werte weiter nimmt.

Über ein paar Tipps woran es liegen könnte wäre ich sehr dankbar.
deets

Sooo, da muss erstmal kraeftigst aufgeraeumt werden.

Zuerstmal schmeisst du bitte alle try/excepts raus. Etwas zu schreiben wie

Code: Alles auswählen

try:
   ...
except:
   print "foo"
ist ein GAÜ - groesstes anzunehmendes Uebel. Denn damit verschleierst du Probleme, da du *alles* abfaengst, gar nicht weisst, *was* schiefgelaufen ist, und im uebrigen - und das ist das schlimmste - danach einfach so weitermachst, als ob nix passiert waere.

Daumenregel: wenn es keine Moeglichkeit gibt, eine Exception sinnvoll zu behandeln (also zB bei einem netzwerk-timeout nochmal eine Verbindung aufzubauen oder sowas), dann lieber gar nicht behandeln. Oder aber fangen, Fehler ausgeben, und dann das Programm *beenden*!!!

Danach nimmst du mal bitte statt range(0, an, 1) nur noch xrange(an). Denn die 0 und die 1 sind sowieso implizit vorgegeben, und xrange baut keine Liste auf, sondern nur einen Iterator. Das spart Speicherplatz. Das ist in deinem Fall wahrscheinlich ziemlich wurscht, aber man sollte sich es erst gar nicht angewoehnen - irgendwann hast du ne Schleife, die ein paar hunderttausend mal laeuft, und vergeutdest ein paar Megabyte fuer nuescht.

Als naechstes ist das hier Unfug:

Code: Alles auswählen

f1 = Popen( vplaninmyz, stdout=PIPE, shell=True).stdout
subprocess.call( vplaninmyz, shell=True)
Oder moechstest du wirklcih dasselbe Programm zweimal aufrufen, beim zweiten mal aber keine Ergebnisse einlesen oder sowas? Theoretisch koennte es natuerlich sinnvoll sein, sieht mir aber eher nach cargo-cult-programming aus. Also, den subprocess.call wegwerfen.

Dann schmeisst du mal den re1 weg, wenn du ihn eh nicht brauchst. Ausserdem schreibst du voellig unnoetigerweise etwas in eine Datei, um es danach aus genau derselben Datei wieder einzulesen. Warum behaelst du es nicht gleich im speicher?

Also

Code: Alles auswählen

text = f1.read()
Dann ersetzt du

Code: Alles auswählen

data2.extend([par])
mit

Code: Alles auswählen

data2.append(par)
Und wenn du das alles gemacht hast, schaust du nochmal, was dein Programm fuer Fehler wirft, wenn es das denn tut.

Und wo genau du eigentlich was anderes erwarten wuerdest.

Last but not least waere es wahrscheinlich besser, hier den paste-bin zu verwenden, und dafuer dein Programm *nicht* zu kuerzen. Sonst ist das, um bei der Analogie von oben zu bleiben, so, als ob du mit der Motorhaube + dem Endtopf in der Werkstatt auflaeufst... aber der Rest des Autos steht zuhause.
kleiner.epsilon
User
Beiträge: 25
Registriert: Sonntag 31. Oktober 2010, 14:31

Hallo deets,
danke für deine schnelle Antwort, du hast mir sehr geholfen. Ich konnte aber nicht alle Punkte umsetzen, erkläre dir auch gleich warum.

1. das subprocess.call (die Ausgabe im Terminal) kann ich später vielleicht weglassen, wenn ich 5000 Durchläufe mache, aber im Moment brauche ich es noch um schnell zu sehen, wie die Parameterschätzung war, oder was ich noch verbessern könnte. Die Ausgabe im Terminal wird dann in eine Datei geschrieben, in der ich mit regulären Ausdrücken nach den Parametern und anderen wichtigen Werten suche.

2. wenn ich data2.extend([par]) statt data2.extend(par) schreibe, kommt '0', '1', '2', '3' statt '0.123'.

3. das re1 brauche ich. Zur Erklärung: entwerder erscheint, re1 oder re2 oder re3 oder re4 bis re11.

Nach den Änderungen funktioniert ein Durchlauf, aber bei mehreren automatisch nacheinander kommt folgende Fehlermeldung:

Traceback (most recent call last):
File "rahmenprogramm-neu.py", line 46, in <module>
str3 = replace_words(str2, word_dic)
File "rahmenprogramm-neu.py", line 36, in replace_words
rc = re.compile('|'.join(map(re.escape, word_dic)))
AttributeError: compile

Ich verstehe nicht, was wie und wo ich ändern soll.
Hier der vollständige Code, habe nur die Dateinamen weggelassen:

Code: Alles auswählen

an = input("Wie viele Durchlaeufe? ")
for lfd in xrange(an):
	eps= 0.8
	mu = 1	# mean
	sigma = 0.4	# standard deviation
	zp1 = gauss(mu,sigma)
	zp2 = gauss(mu,sigma)
	zp3 = gauss(mu,sigma)
	zp4 = gauss(mu,sigma)
	zp5 = gauss(mu,sigma)

	def replace_words(text, word_dic):
	    # Datei einlesen, Woerter in Dictionary ersetzen und geaenderten Text zurueck geben
	    rc = re.compile('|'.join(map(re.escape, word_dic)))
	    def translate(match):
	        return word_dic[match.group(0)]
	    return rc.sub(translate, text)
	fin = open(inmy, "r")
	str2 = fin.read()
	fin.close()
	word_dic = {'MYP1': str(zp1), 'MYP2': str(zp2), 'MYP3': str(zp3), 'MYP4': str(zp4), 'MYP5': str(zp5), 'MYEPS':str(eps)}	
	str3 = replace_words(str2, word_dic)
	fout = open(inmyz, "w")
	fout.write(str3)
	fout.close()
# Parameterschaetzung, Ausgabe speichern in 'vplaninausgabemyz'
	f1 = Popen( vplaninmyz, stdout=PIPE, shell=True).stdout
	subprocess.call( vplaninmyz, shell=True) # Terminalausgabe, spaeter weglassen
	ausgabe = open( vplaninausgabemyz, 'w+')
	for f in f1:
		ausgabe.write(str(f))
	ausgabe.close()
	f1.close()
# die Startwerte (Zufallszahlen) aus vplan einlesen (fuer die Reproduktion)
	rezp1 = compile('p1=kr1 [+|-]?\w[.]\w+',I)
	rezp2 = compile('p2=e [+|-]?\w[.]\w+',I)
	rezp3 = compile('p3=k1 [+|-]?\w[.]\w+',I)
	rezp4 = compile('p4=ekat [+|-]?\w[.]\w+',I)
	rezp5 = compile('p5=lambda [+|-]?\w[.]\w+',I)
	f3 = open( inmyz )
	text3 = f3.read()
	listesuch3 = rezp1, rezp2, rezp3, rezp4, rezp5
	zufallszahlen =[]
	for re in listesuch3:
		m = re.search(text3)
		n = m.group()
		p = n.split()
		par = p[1]
		zufallszahlen.extend([par])
	print zufallszahlen
	f3.close()
# 'vplaninausgabemyz' nach den 3 Fehlerarten durchsuchen, in 'errormess' speichern
	try: 
		re1 = compile('No corrector convergence', I)
		re2 = compile('divergence', I) #DIVERGENCE: Iteration Terminated after xx Iteration
		re3 = compile('Matrix',I) 	#Matrix hat nicht vollen Spaltenrang
		re4 = compile('SQUARES \s+\d+[.]\d*[E]?[+|-]?\d?\d?\d?',I)
		re5 = compile('p1: [+|-]?\d[.]?\d*',I)
		re6 = compile('p2: [+|-]?\d[.]?\d*',I)
		re7 = compile('p3: [+|-]?\d[.]?\d*',I)
		re8 = compile('p4: [+|-]?\d[.]?\d*',I)
		re9 = compile('p5: [+|-]?\d[.]?\d*',I)
		re11= compile('Residual: [+|-]?\d[.]\d*',I)

		f2 = open( vplaninausgabemyz )
		text = f2.read()

		listesuch2 =  re5, re6, re7, re8, re9
		data2 =[]
		for re in listesuch2:
			m = re.search(text, 1500)
			n = m.group()
			p = n.split()
			par = p[1]
			data2.extend([par])
		print data2

		m4 = re4.search(text,1500)
		n4 = m4.group()		
		p4 = n4.split()
		lsqu = p4[1]
				
		m11 = re11.search(text,1800)
		n11 = m11.group()		
		p11 = n11.split()
		residual = p11[1]
		
		if re1.search(text):
			datei = open( pardateineu, 'a')
			datei.write("\n")	#zur besseren Uebersicht neue Zeile bei Fehler
			datei.close()
	
			errordatei = open( errormessmyz, 'a')
			errordatei.write("%5d "%lfd)			
			errordatei.write("%.2f   "%eps)
			errordatei.write("%.2f   "%sigma)
			for p in zufallszahlen:
				errordatei.write("%.12f  "%(string.atof(p),))
			errordatei.write("No corrector convergence")
	
			errordatei.write("\n")
			errordatei.close()
			continue
			
		elif re2.search(text):
			datei = open( pardateineu, 'a')
			datei.write("\n")	#zur besseren Uebersicht neue Zeile bei Fehler
			datei.close()
	
			errordatei = open( errormessmyz, 'a')
			errordatei.write("%5d "%lfd)			
			errordatei.write("%.2f   "%eps)
			errordatei.write("%.2f   "%sigma)
			for p in zufallszahlen:
				errordatei.write("%.12f  "%(string.atof(p),))
			errordatei.write("divergence")
			for a in data2:
				errordatei.write("%.7f  "%(string.atof(a),))
			errordatei.write("\n")
			errordatei.close()
			continue
	
		elif re3.search(text):
			datei = open( pardateineu, 'a')
			datei.write("\n")	#zur besseren Uebersicht neue Zeile bei Fehler
			datei.close()
			errordatei = open( errormessmyz, 'a')
			errordatei.write("%5d "%lfd)			
			errordatei.write("%.2f   "%eps)
			errordatei.write("%.2f   "%sigma)
			for p in zufallszahlen:
				errordatei.write("%.12f  "%(string.atof(p),))
			errordatei.write("Matrix nicht voller Spaltenrang")
			errordatei.write("\n")
			errordatei.close()
			continue
	
		f2.close()
	except:
		print 'Fehler bei regulaeren Ausdruecken'
# Parameterliste in Datei 'pardateineu.txt' speichern
	datendatei = open( pardateineu, 'a')
	for p in data2:
		datendatei.write("  %.7f"%(string.atof(p),))
	datendatei.write("  %5d  %.1f  %.1f  %10s  %25s  "%(lfd, eps, sigma, residual, lsqu))	
	for q in zufallszahlen:
		datendatei.write("%.12f "%(string.atof(q),))
	datendatei.write("\n")
	datendatei.close()
BlackJack

@kleiner.epsilon: Zu 1.: Kannst Du da nicht den zweiten Aufruf weglassen und beim Entwickeln in der Schleife die Ausgabe nicht nur in die Datei schreiben, sondern auch zusätzlich ``print``\en?

Zu 2.: Du sollst nicht ``extend(par)`` nehmen, sondern ``append(par)``.

Zu 3.: Wenn Du Namen durchnummerierst, dann willst Du in der Regel Listen verwenden. So auch hier. Du musst die Elemente nicht vorher an Namen binden.

Zum AttributeError: ``for re in listesuch2:`` bindet den Namen `re` neu. Und das Objekt hat dann halt kein Attribut `compile`.

Das ist immer noch alles zu unübersichtlich. Hast *Du* denn überhaupt im Kopf wie viele Namen da verwendet werden? Und welcher Name an welcher Stelle woran gebunden ist? Und welcher Ausführungspfad zu einer Neubindung führt -- oder eben auch nicht? Und bist Du sicher dass Du nicht, genau wie bei `re`, noch andere Namen für verschiedene Dinge verwendest?

Teil das ganze mal in Funktionen mit einer überschaubarer Menge von Variablen auf.

Ausserdem liesse sich durch Funktionen sicher auch an der ein oder anderen Stelle ein wenig verkürzen. Da sind ein paar sich wiederholende Muster drin.

Warum definierst Du `replace_words` in der Schleife ständig neu?

`f2` wird im Falle einer Ausnahme nicht wieder geschlossen. Man sollte zum Schliessen von Dateien sowieso besser die ``with``-Anweisung verwenden. Das ständige öffnen und schliessen ist auch nicht so toll.

Wo hast Du `string.atof()` ausgegraben? Das verwendet man schon seit Jahren nicht mehr -- seit man dafür `float()` verwenden kann.
BlackJack

@kleiner.epsilon: Noch was zum Aufräumen: Du hast anscheinend sowohl `re` als auch alles in `re` per Sternchen-Import in Deinen Namensraum geholt. Letzteres solltest Du entfernen und explizit über `re` auf die Namen zugreifen. Eventuell hast Du das gleiche bei `subprocess` gemacht? Sternchen-Importe sollte man in Programmen generell vermeiden.

``continue`` ist übrigens auch eine Anweisung die man nur mit bedacht einsetzen sollte. Vielleicht liegt es sogar daran. Zumindest die Datei `f2` wird deswegen sicher öfter nicht ordnungsgemäss geschlossen. Und soll die `datendatei` am Ende der Schleife bei *jedem* Schleifendurchlauf beschrieben werden? Wird sie nämlich nicht.

Noch mal zu den Namen und der Anzahl: Der Code enthält 67 davon! Die alle im gleichen -- und zwar Modulglobalen -- Namensraum herum schwirren. Das kann sich doch kein Mensch merken. Wenn Du den Inhalt von `re` per Sternchen importiert hast, dann sind es sogar 91 Namen. Wobei das nur Mindestangaben sind -- Du hast ja nicht den kompletten Quelltext gezeigt.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@kleiner.epsilon:

Magst du eigentlich Python nicht oder wieso hebelst du quasi seine Ausnahmebehandlung mit diesem ellenlangen try-except-Block aus? :)

Wenn du nicht möchtest, dass der Benutzer mögliche Fehler deines Programms sehen kann, dann schreib dein Programm doch am besten so um, dass keine Fehler entstehen. Das Abfangen von Ausnahmen machst du entsprechend explizit für die Stellen, wo die Fehler auftreten können. Idealerweise umgibt so ein try-except-Konstrukt immer nur genau einen Aufruf und spezifiziert natürlich auch die Ausnahme(n), die man behandeln möchte und nicht einfach so allgemein *jede* Ausnahme.
kleiner.epsilon
User
Beiträge: 25
Registriert: Sonntag 31. Oktober 2010, 14:31

Danke für eure Antworten und Anregungen, dadurch habe ich nämlich den Fehler gefunden:
BlackJack hat geschrieben: Zum AttributeError: ``for re in listesuch2:`` bindet den Namen `re` neu. Und das Objekt hat dann halt kein Attribut `compile`.
:oops: Ich hab tatsächlich einen Namen zweimal verwendet ...
Hab inzwischen eure Tipps umgesetzt, der Code sieht inzwischen wieder ganz anders aus.
Vielen Dank.
Antworten