Hi,
mir macht mal wieder Pythons eigenwilliger Umgang mit Variablen/Objekten zu schaffen. Nun möchte ich einige Experimente mit verschiedenen Parametern durchführen. Implementiert habe ich das ganze als Klassen und möchte die einzelnen Durchläufe als Instanzen abwickeln. Nun bekomme ich es einfach nicht in den Griff, das die Instanzen sich nicht gegenseitig beeinflussen (Python macht es einem da ja leider nicht wirklich leicht). Sprich ich habe schon mehrfach feststellen müssen das nach Durchlauf eines Experimentes und der Erzeugung einer neuen Testumgebung mit neuen Parametern irgendwelche Unterobjekte, Listen etc. mit den alten Werten initialisiert geblieben sind, vom neuen Objekt mitverwendet werden und mir die Ergebnisse verfälschen.
Daher meine Frage: Gibt es irgend eine sichere Methode in Python selber alles auf "Null" zu setzen - also sprich in einen Zustand zurück zu kehren, in dem sich Python verhält als wäre das Skript gerade komplett neu gestartet worden? Damit könnte ich dann sicher sein, dass meine Ergebnisse rein sind, wenn ich versuche jede Stelle an der alte Daten Ergebnisse verfälschen, per Hand zu finden und zu korrigieren habe ich ja immer noch das Risiko, dass ich irgendetwas übersehen habe oder ich ein ungewöhnliches Verhalten von Python nicht kenne.
"Alles" wieder auf null setzen
-
- User
- Beiträge: 63
- Registriert: Donnerstag 20. November 2003, 13:45
- Wohnort: Frankfurt/M.
-
- User
- Beiträge: 456
- Registriert: Mittwoch 15. April 2009, 14:11
Wenn du auf die Geschichte anspielst: anspielst, dann sei dir die Doku empfohlen. Wenn's das nicht ist, bitte ich dich ein bisschen konkreter zu werden. Falls dir der obige Code nix sagt, führ die Funktion einfach ein paar mal aus.
Das ganze löst man in der Regel, indem man param auf None setzt und eine leere Liste erzeugt, falls param None ist.
Grüße,
anogayales
Code: Alles auswählen
def test(param=[]):
param.append(4)
print param

Grüße,
anogayales
@AllesMeins: Du meinst, dass sich diverse Exemplare der selben Klasse beeinflussen? Sowas kann eigentlich nicht passieren, sofern man nicht mit irgendwelchen "klugen Tricks" die Klassenattribute verändert oder ähnliches. Ansonsten kann es sein, dass du gar nicht mit unterschiedlichen Exemplaren arbeitest, sondern immer auf den selben. Der gezeigte Code mit der leeren Liste als Defaultargument ist ein gutes Beispiel dafür: Python erstellt dieses Objekt für die Funktionssignatur exakt einmal, anschließend wird es in der Funktion verändert und hat dann bei nachfolgenden Aufrufen immer noch den Inhalt, den es am Ende des vorangegangenen Aufrufs hatte. Und dieser wird wohlgemerkt als Basis für weitere Veränderungen genutzt. An dieses Verhalten muss man sich halt gewöhnen. Als Faustregel gilt also: Objekte, die man verändert, grundsätzlich nicht als Defaultwert setzen. Das kann letztlich zu viel Verwirrung führen.
-
- User
- Beiträge: 63
- Registriert: Donnerstag 20. November 2003, 13:45
- Wohnort: Frankfurt/M.
Ja, Beispielsweise solche Geschichten. Oder das Initialisieren von Listen im Kopf einer Klasse oder was weiss ich, was es da noch für Fallen gibt. Und eben da ich möglicherweise nicht alle kenne suche ich nach einer Möglichkeit einfach alles auf Null zu setzen. Ich hätte gerne das Python einfach alle Variablen, Objekte etc. löscht und erst dann mit den nächsten Schritt weitermacht. Also irgendwie sowas:
Und nach "LÖSCHE ALLES" soll sich Python möglichst so verhalten als ob die ersten 3 Zeilen gar nicht da gewesen wären bzw. so als würde das Programm erst nach Zeile 5 beginnen.
Code: Alles auswählen
handler = Experiment("parameter1","parameter2")
handler.run()
handler.speichereErgebnisInDatei()
LÖSCHE ALLES
handler = Experiment("parameter3","parameter4")
handler.run()
handler.speichereErgebnisInDatei()
Also ich würde ja sagen, dass das, was Dir zu schaffen macht genau das ist, was man ja über solche Experimente/Tests herausfinden möchte: Gibt es unsaubere Stellen in meinem Code, durch den unerwünschte Seiteneffekte entstehen?
Ich würde das nicht über einen Resetknopf, sondern durch Korrektur im Code lösen.
Nun ja, wie auch immer, vielleicht hilft Dir ja globals() und oder locals() weiter.
mutetella
EDIT: Manchmal kann es ja durchaus sein, dass nach längerem "rumgeteste" manches recht eigenartig reagiert. Wenn das Testen innerhalb des Interpreters stattfindet, hilft mir da schon auch mal ein 'reset' weiter.
Wobei es dieses 'reset' meines Wissens nur in 'iPython' gibt.
Ich würde das nicht über einen Resetknopf, sondern durch Korrektur im Code lösen.
Nun ja, wie auch immer, vielleicht hilft Dir ja globals() und oder locals() weiter.
mutetella
EDIT: Manchmal kann es ja durchaus sein, dass nach längerem "rumgeteste" manches recht eigenartig reagiert. Wenn das Testen innerhalb des Interpreters stattfindet, hilft mir da schon auch mal ein 'reset' weiter.
Wobei es dieses 'reset' meines Wissens nur in 'iPython' gibt.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit
)

-
- User
- Beiträge: 63
- Registriert: Donnerstag 20. November 2003, 13:45
- Wohnort: Frankfurt/M.
Nein, möchte ich nichtmutetella hat geschrieben:Also ich würde ja sagen, dass das, was Dir zu schaffen macht genau das ist, was man ja über solche Experimente/Tests herausfinden möchte: Gibt es unsaubere Stellen in meinem Code, durch den unerwünschte Seiteneffekte entstehen?

Das ganze ist nur ein Framework um das Verhalten verschiedener algorithmischer Ansätze zu testen und kein Code für irgend ein Produktiv-System. Sprich: An sich stören mich die Seiteneffekte überhaupt nicht, solange sie nicht auf verschiedene Test-Instanzen durchschlagen. Und da es Experimente sind ist es auch nicht so wirklich einfach solche Effekte zu entdecken, da sich ja möglicherweise nur das Ergebnis ein bisschen ändert, ich aber keinen Soll-Wert habe (wenn ich wüsste was rauskommen soll, müsste ich ja keine Experimente machen).
Das hört sich nach einem Designfehler an. In der Doku zu Flask ist als Beispiel ganz schön beschrieben, wie man mit application-factories so etwas elegant lösen kann: http://flask.pocoo.org/docs/patterns/appfactories/
- pillmuncher
- User
- Beiträge: 1527
- Registriert: Samstag 21. März 2009, 22:59
- Wohnort: Pfaffenwinkel
Ich verstehe nicht recht, was an Pythons Umgang mit Variablen eigenwillig sein soll. Meinst du vielleicht sowas:
?
Code: Alles auswählen
>>> x = [1, 2, 3]
>>> y = x
>>> y[1] = 4
>>> x
[1, 4, 3]
In specifications, Murphy's Law supersedes Ohm's.
Hi du kannst mit dem "del" Statement im fast alles aus dem Speicher entfernen. Wenn das dein Problem nicht löst, versteh ich deine Frage nicht. Dann verzeih mir will ja auch nur helfen, bin nämlich erst seit zwei oder einem Jahr mit Python und Programmieren vertraut:
Code: Alles auswählen
class X():
def __init__(self,liste=[]):
self.liste=liste
print(self.liste)
def add_(self,etwas):
self.liste.append(etwas)
print(self.liste)
a=X(["hi"])
a.add_(["ne","tie"])
del a
try:
print(a)
except NameError:
print("NameError")
a=X("5")
del a
#############################################################
class X(list):
def __init__(self,liste=[]):
list.__init__(self)
self.append(liste)
print(self)
def copyList(self):
return self[:]
def sameID(self):
return self
a=X("8")
b=a.copyList()
print(b,"b")
print(a,"a")
a.append("hi")
print(b,"b")
print(a,"a")
del b
b=a.sameID()
print(b,"b")
print(a,"a")
b.append("hi")
print(b,"b")
print(a,"a")
print(id(a))
print(id(b))
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Eigentlich kann man das nicht, da Python keine manuelle Speicherverwaltung bietet. Man kann aber mit `del` Namen löschen, was dann dazu führen kann, dass ein Objekt nicht mehr referenziert ist und vom Garbage Collector gelöscht wird.Newcomer hat geschrieben:Hi du kannst mit dem "del" Statement im fast alles aus dem Speicher entfernen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Wenn jemand Python programmieren möchte ohne Python zu lernen und eine magische Möglichkeit sucht Programmfehler zu beseitigen ohne die Fehler im Programm zu suchen, dürfte wohl nicht wirklich viel helfen.
-
- User
- Beiträge: 63
- Registriert: Donnerstag 20. November 2003, 13:45
- Wohnort: Frankfurt/M.
Auch wenn mich deine Überheblichkeit doch etwas stört möchte ich dir gerne antworten:BlackJack hat geschrieben:Wenn jemand Python programmieren möchte ohne Python zu lernen und eine magische Möglichkeit sucht Programmfehler zu beseitigen ohne die Fehler im Programm zu suchen, dürfte wohl nicht wirklich viel helfen.
Ich suche keine "magische" Möglichkeit, sondern durchaus Dinge die im Rahmen einer Programmiersprache liegen könnten und damit halte ich es für durchaus legitim zu fragen, ob es etwas vergleichbares gibt (abgesehen davon, dass soetwas gar nicht nötig wäre, wenn Python seine Variablen zwischen Objekten anständig getrennt halten würde - aber das ist ein anderes Thema). Vor allem, da es üblicherweise der sicherere Weg ist, wenn möglich, einfach "reinen Tisch" zu machen, anstatt sich darauf zu verlassen dass man schon nichts übersehen haben wird.
Um das Thema zum Abschluss zu bringen: Ich habe das Problem nun gelöst indem ich meine Test-Programme einfach jedesmal von außen per Bash-Skript neu starten lasse, anstatt Python-Intern mit Objekten zu arbeiten. Das ist zwar nicht besonders schön, stellt aber wenigstens sicher das die Zwischenergebnisse der alten Berechnungen weg sind und nicht zwischen den einzelnen Durchläufen wandern...
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
AllesMeins hat geschrieben: Um das Thema zum Abschluss zu bringen: Ich habe das Problem nun gelöst indem ich meine Test-Programme einfach jedesmal von außen per Bash-Skript neu starten lasse, anstatt Python-Intern mit Objekten zu arbeiten. Das ist zwar nicht besonders schön, stellt aber wenigstens sicher das die Zwischenergebnisse der alten Berechnungen weg sind und nicht zwischen den einzelnen Durchläufen wandern...
Code: Alles auswählen
handler = Experiment("parameter1","parameter2")
handler.run()
handler.speichereErgebnisInDatei()
LÖSCHE ALLES
handler = Experiment("parameter3","parameter4")
handler.run()
handler.speichereErgebnisInDatei()
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
-
- User
- Beiträge: 63
- Registriert: Donnerstag 20. November 2003, 13:45
- Wohnort: Frankfurt/M.
Ich auch nicht hundert Prozent. Ein Beispiel-Falle die ich kenne wäre soetwas:Hyperion hat geschrieben:Ich verstehe nicht, inwiefern bei dem von Dir gezeigten Code noch Zwischenergebnisse enthalten sein können?
Code: Alles auswählen
class Experiment:
data = list()
def addData(self, item):
self.data.append(item)
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Ah, ok. Naja, den Unterschied zwischen Klassen- und Objektattributen sollte man schon kennen - tust Du ja offensichtlich auch. Mir fallen da jetzt spontan keine anderen Szenarien ein, bei denen (autonome) Objekte automatisch bestehende Objekte angeflantscht bekommen.
Sofern Du die neu erstellten Objekte nicht in eine "Umgebung" schmeißt, die für solche Effekte sorgt, kann da nix passieren. Und solche Sachen sollten imho dokumentiert sein.
Wenn Du Dir unsicher bist, dann könntest Du doch einfach mal Tests fahren, die einmal in einer "Schleife" Experimente berechnen und diese mit manuell gestarteten Tests bzw. deren Ergebnissen vergleichen. Wenn diese identisch sind, treten wohl keine Nebeneffekte auf.
Sofern Du die neu erstellten Objekte nicht in eine "Umgebung" schmeißt, die für solche Effekte sorgt, kann da nix passieren. Und solche Sachen sollten imho dokumentiert sein.
Wenn Du Dir unsicher bist, dann könntest Du doch einfach mal Tests fahren, die einmal in einer "Schleife" Experimente berechnen und diese mit manuell gestarteten Tests bzw. deren Ergebnissen vergleichen. Wenn diese identisch sind, treten wohl keine Nebeneffekte auf.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Naja, schlecter Code der den globalen State modifiziert ist eben das - schlecht. Das hast du ja in jeder anderen Sprache auch. Und ja, ich hatte auch mal so einen Fall dass eine "Library" nur einen Aufruf zugelassen hat weil danach der State der Objekte so kaputt war dass es nicht mehr funktioniert hat. Da hab ich nach einigem fluchen später ``multiprocessing`` verwendet.AllesMeins hat geschrieben:Soetwas habe ich nirgends gemacht, Tatsache ist aber das ich Python (oder meinen Python-Kenntnissen) nicht (mehr) traue und ich mir recht sicher bin, dass es dort noch einige vergleichbare Fallen gibt, die ich bisher nicht kenne.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
-
- User
- Beiträge: 63
- Registriert: Donnerstag 20. November 2003, 13:45
- Wohnort: Frankfurt/M.
Das bestreite ich ja auch gar nicht. Meine Erfahrung ist nur, dass man den globalen State in Python leichter unabsichtlich modifiziert als in anderen Sprachen. Da muss man dann ja meistens ein global davor setzen oder irgendwie anders explizit ausdrücken, dass irgend eine Variable global verarbeitet werden soll.Leonidas hat geschrieben:Naja, schlecter Code der den globalen State modifiziert ist eben das - schlecht. Das hast du ja in jeder anderen Sprache auch.
@AllesMeins: Im obigen Beispiel zeigst Du ein Klassenattribut, und wunderst Dich, dass sich dieses Klassenattribut auch tatsächlich wie ein Klassenattribut verhält, sprich zwischen Klassenexemplaren geteilt wird, und führst es als Beleg dafür an, dass man den globalen Zustand leicht unabsichtlich modifizieren könne.
Allerdings weiß jeder halbwegs erfahrene Python-Programmierer, wie sich der Quelltext im Beispiel verhalten würde, und würde sowas mithin auch nicht schreiben, ohne die Konsequenzen zu kennen. Daher ist das Beispiel auch praxisfern, denn kein Python-Programmierer würde veränderliche Objekte im Namensraum der Klasse deklarieren, wenn nicht explizit gewollt ist, dass das Objekt zwischen Exemplaren der Klasse geteilt wird (was allerdings ziemlich schlechter Stil wäre). „Unabsichtlich“ ist der Effekt des gezeigten Beispiels mithin nur und ausschließlich dann, wenn man Python nicht beherrscht.
Allerdings weiß jeder halbwegs erfahrene Python-Programmierer, wie sich der Quelltext im Beispiel verhalten würde, und würde sowas mithin auch nicht schreiben, ohne die Konsequenzen zu kennen. Daher ist das Beispiel auch praxisfern, denn kein Python-Programmierer würde veränderliche Objekte im Namensraum der Klasse deklarieren, wenn nicht explizit gewollt ist, dass das Objekt zwischen Exemplaren der Klasse geteilt wird (was allerdings ziemlich schlechter Stil wäre). „Unabsichtlich“ ist der Effekt des gezeigten Beispiels mithin nur und ausschließlich dann, wenn man Python nicht beherrscht.