"Alles" wieder auf null setzen

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.
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

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.
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Wenn du auf die Geschichte anspielst:

Code: Alles auswählen

def test(param=[]):
    param.append(4)
    print param
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
Benutzeravatar
snafu
User
Beiträge: 6751
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@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.
AllesMeins
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:

Code: Alles auswählen

handler = Experiment("parameter1","parameter2")
handler.run()
handler.speichereErgebnisInDatei()

LÖSCHE ALLES

handler = Experiment("parameter3","parameter4")
handler.run()
handler.speichereErgebnisInDatei()
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.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

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.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

mutetella 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?
Nein, möchte ich nicht :D
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).
.robert
User
Beiträge: 274
Registriert: Mittwoch 25. April 2007, 17:59

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/
Benutzeravatar
pillmuncher
User
Beiträge: 1488
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.
Newcomer
User
Beiträge: 131
Registriert: Sonntag 15. Mai 2011, 20:41

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))
        
        
        
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Newcomer hat geschrieben:Hi du kannst mit dem "del" Statement im fast alles aus dem Speicher entfernen.
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.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Newcomer
User
Beiträge: 131
Registriert: Sonntag 15. Mai 2011, 20:41

genau das meinte ich ja auch, dann "kennt" python die Variable nicht mehr und die listen (Objekte) beeinflussen sich nicht mehr gegenseitig.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ähm, das klingt mir nicht nach einem Problem das man mit ``del`` lösen kann.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

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.
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

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.
Auch wenn mich deine Überheblichkeit doch etwas stört möchte ich dir gerne antworten:
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...
Benutzeravatar
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()
Ich verstehe nicht, inwiefern bei dem von Dir gezeigten Code noch Zwischenergebnisse enthalten sein können?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

Hyperion hat geschrieben:Ich verstehe nicht, inwiefern bei dem von Dir gezeigten Code noch Zwischenergebnisse enthalten sein können?
Ich auch nicht hundert Prozent. Ein Beispiel-Falle die ich kenne wäre soetwas:

Code: Alles auswählen

class Experiment:
  data = list()

  def addData(self, item):
    self.data.append(item)

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. Und solche Probleme zu finden ist fast unmöglich, wenn man experimentelle Berechnungen durchführt, deren Ergebniss ich nicht kenne. Sagen wir ich würde jetzt als Experiment einfach den Mittelwert von data berechnen wollen - da würde es in dem oben beschriebenen Szenario furchtbar falsche Ergebnisse geben, aber nicht wirklich auffallen wenn die Ausgangsdaten ausreichend unbekannt sind. Und um da absolut auf Nummer sicher zu gehen will ich einfach den "kompletten" Speicher von Python löschen. Und das mache ich jetzt extern, da es intern scheinbar nicht geht.
Benutzeravatar
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.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

Leonidas hat geschrieben:Naja, schlecter Code der den globalen State modifiziert ist eben das - schlecht. Das hast du ja in jeder anderen Sprache auch.
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.
lunar

@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.
Antworten