Variablen automatisch sichern / Löschmethode überschreiben

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.
Gerenuk
User
Beiträge: 69
Registriert: Donnerstag 21. Januar 2010, 22:27

Variablen automatisch sichern / Löschmethode überschreiben

Beitragvon Gerenuk » Sonntag 15. Mai 2011, 17:24

Zum Debuggen würde ich gerne, dass in normalen Programläufen einige Variablen in Files gesichert werden.

Ich stelle es mir als Aufruf so vor

Code: Alles auswählen

x=...
store_var(x, "x.dat")
...

und nachdem das Programm gelaufen ist würde ich gerne den letzten Wert von x in x.dat nachlesen (ist ein pickle dump oder vielleicht lesbareres YAML besser?).

Dazu würde man vermutlich das Löschen umbiegen also irgendwie die __del__ Methode durch store_var verändern lassen?! Bloß irgendwie kriege ich das nicht gebacken :(
Weiß jemand wie das gehen würde? Funktioniert es dann auch für Objekte wie int?
Benutzeravatar
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon cofi » Sonntag 15. Mai 2011, 17:55

Gerenuk hat geschrieben:Dazu würde man vermutlich das Löschen umbiegen also irgendwie die __del__ Methode durch store_var verändern lassen?! Bloß irgendwie kriege ich das nicht gebacken :(
Weiß jemand wie das gehen würde? Funktioniert es dann auch für Objekte wie int?


Nun das geht, Stichwort `monkey patching`. Aber built-ins wie `int` bekommst du damit nicht.
Daneben ist es ziemlich unschoen IO im "Destruktor" zu machen -- als ob "normaler" Code im "Destruktor" nich schon schlimm genug waere.

Von dem Weg wuerd ich dir abraten, überleg dir lieber ein sinnvolles Logging-Konzept; v.a. da post-mortem Analyse dann evtl sinnvoller vonstatten geht, da man den Fehlerweg evtl nachvollziehen kann.
Gerenuk
User
Beiträge: 69
Registriert: Donnerstag 21. Januar 2010, 22:27

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon Gerenuk » Sonntag 15. Mai 2011, 18:12

Und wie würde man das einpatchen? Es scheint auf dem naheliegendsten Weg komme ich an __del__ nachträglich nicht ran :(
Natürlich gefällt ein Designkonzept nicht immer jedem, aber die Frage ist ja wie es geht ungeachtet der eigenen Philosophie :)

Ich habe halt ein normales Programm und will da nicht dieses Debugzeug tief reincodieren sondern es eher beliebig von außen dranspielen. Klar könnte ich print statements einbauen, aber das ist hässlich, weil ich dann immer suchen muss, wo denn der finale Zustand des Objektes ist. Und post-mortem ist das auch nicht, weil es mir um gewöhnliche Programmabläufe geht, wo ich eher logische Fehler in den Daten habe.
lunar
Python-Forum Veteran
Beiträge: 5748
Registriert: Freitag 4. August 2006, 11:29

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon lunar » Sonntag 15. Mai 2011, 18:22

@Gerenuk: Dieses „Designkonzept“ wird fast überhaupt niemandem gefallen, der einigermaßen vernünftig denkt. Schon das Wort „Designkonzept“ ist eigentlich zu viel des Guten für diese Idee. Nichts für ungut :)

Ich schließe mich cofi an, und rate lieber zu umfassendem und umfangreichem Logging, und zwar nicht mit "print", sondern mit "logging" aus der Standardbibliothek (oder mit dem Drittmodul logbook, wenn man es moderner mag). Das ist kein „Debugzeug“, sondern ein üblicher und sauberer Weg, den Zustand eines Programms nachzuverfolgen. Jeder Dienst, der auf Deinem System so läuft, benutzt das, um über seinen Zustand zu informieren (unter Linux mittels syslog nach "/var/log/", unter Windows ins Ereignislog, das über die Systemverwaltung erreichbar ist). Was für Dienste seit Jahrzehnten funktioniert, kann für Dich so schlecht nicht sein. ;)

Im Gegensatz zu Deiner Idee ist dieser Ansatz sauber, weil das Logging explizit ohne Magie geschieht, und flexibler, weil man das Logging von außen konfigurieren und somit beispielsweise die Debugging-Ausgaben im Produktivbetrieb abschalten kann, ohne den Quelltext verändern zu müssen.

Dein Vorhaben dagegen finde ich ziemlich bedenklich. Ich halte die Gefahr für groß, dass Du mit solcher Magie, mit solch tiefen Eingriffen in die Interna von Objekten und des Interpreters überhaupt erst neue Fehler einführst, die nicht mehr einfach zu debuggen sind, eben weil sie in den Interna von Objekten geschehen. In ".__del__()" können beispielsweise bestimmte Namen gar nicht mehr existieren, was dann zu Ausnahmen bei Erzeugen der Debugging-Ausgabe führen kann. Damit erreichst Du also mehr das Gegenteil dessen, was Du erreichen willst: Statt die Fehlersuche zu erleichtern, führst Du neue, noch schwerer zu findenden Fehler ein.

Außerdem ist der Ansatz, „einige Variablen“ zu sichern, sowieso von vorne herein zu scheitern verurteilt, weil Du gemäß Murphys Law eben genau die Variable, die für die Analyse des gerade aufgetretenen Fehlers entscheidend wäre, nicht gesichert hast ;)

Im Allgemeinen ist die Idee eh nicht umsetzbar. Man kann nicht einfach jedes existierende Objekt nachträglich verändern. Du musst jedwede Klasse, die Du verwendest, mit einer eigenen ".__del__()" Implementierung patchen (auf Exemplaren geht das nicht), und selbst wenn Du dabei keine Klasse vergessen hast, bleibt immer noch das Problem, dass ".__del__()" nicht zuverlässig aufgerufen wird.
Benutzeravatar
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon cofi » Sonntag 15. Mai 2011, 18:45

Gerenuk hat geschrieben:Und wie würde man das einpatchen? Es scheint auf dem naheliegendsten Weg komme ich an __del__ nachträglich nicht ran :(

Sicher:

Code: Alles auswählen

In [1]: class Klass(object):
   ...:     pass

In [2]: def print_(self): print "hello there"

In [3]: a = Klass()

In [4]: Klass.f = print_

In [4]: a.f()
hello there


Zumindet kann ich mir keinen einfacheren Weg vorstellen, aber du handelst dir unglaublich viele Probleme ein, wie lunar schon ausgefuehrt hat.
Gerenuk
User
Beiträge: 69
Registriert: Donnerstag 21. Januar 2010, 22:27

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon Gerenuk » Sonntag 15. Mai 2011, 18:46

Hmm, also ich finde da ziemlich unproduktiv, wenn man zwar keine Antwort gibt aber dafür erstmal langwierig die Frage in Frage stellt. Es soll mal meine Sorge sein ob ich die richtigen Variablen auswähle, denn schließlich verantworte ich selbst diesen Code. Ich habe mir das mit meiner speziellen Anforderung überlegt und es wäre zu komplex jetzt erst alle Details erläutern zu müssen nur um mich zu rechtfertigen und auch zu erklären wieso logging (was ich sonst viel nutze) hier nicht praktisch ist. Die Alternativen kenne ich gut, aber trotzdem Danke für die Zusammenfassung.

Also, möchte mir jemand beim Monkey-Patching helfen oder zumindest Ansätze zeigen?
Zuletzt geändert von Gerenuk am Sonntag 15. Mai 2011, 18:49, insgesamt 1-mal geändert.
Gerenuk
User
Beiträge: 69
Registriert: Donnerstag 21. Januar 2010, 22:27

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon Gerenuk » Sonntag 15. Mai 2011, 18:47

EDIT:

Jetzt geht es doch. Anscheinend ist __del__ eine Klassenfunktion

Code: Alles auswählen

class Test(object):
    def __del__(self):
        print("Old del")

def p(self):
    print("New del")

a=Test()
Test.__del__=p
del a

Hat jemand eine Idee wie man store_var umsetzen könnte? Hmm, ich finde das verwirrend ... aber notwendig ;)
Und hmm, was ist wenn ich nur einzelne Objekte speichern will? Dann müsste ich die Klasse dynamisch ändern?! Huch, wie geht das denn?
Benutzeravatar
pillmuncher
User
Beiträge: 985
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon pillmuncher » Sonntag 15. Mai 2011, 20:34

Gerenuk hat geschrieben:Anscheinend ist __del__ eine Klassenfunktion
__del__ ist keine Klassenfunktion, sondern eine sog. special method. In der Doku zu special methods steht "For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary".

Gerenuk hat geschrieben:Hat jemand eine Idee wie man store_var umsetzen könnte? Hmm, ich finde das verwirrend ... aber notwendig ;) Und hmm, was ist wenn ich nur einzelne Objekte speichern will? Dann müsste ich die Klasse dynamisch ändern?! Huch, wie geht das denn?
Das, was du vorhast, wird nicht funktionieren. In der Doku zu object.__del__() steht "Called when the instance is about to be destroyed. [...] It is not guaranteed that __del__() methods are called for objects that still exist when the interpreter exits." oder auf deutsch: wenn ein Objekt zerstört wird, wird __del__ aufgerufen, außer es wird nicht aufgerufen. IAW, selbst, wenn es dir gelingen sollte, store_var() und __del__-Methoden für alle relevanten Objekte so zu schreiben, dass keine weiteren Fehler oder desaströsen Nebeneffekte auftreten, dann ist immer noch nicht garantiert, dass in x.dat der letzte Wert steht, den x hatte. Beispiel:

Code: Alles auswählen

import sys
from super_module_that_provides_the_store_var_magic import store_var, write_magically_to_file

class MyObjectWithDel(object):
    def __init__(self, number):
        self.number = number
    def __del__(self):
        write_magically_to_file(key=self, value=self.number)

x = MyObjectWithDel(1) # einmal
store_var(x, 'x.dat')  # registrieren zum späteren magischen speichern

x = MyObjectWithDel(2) # und nochmal
store_var(x, 'x.dat')  # registrieren zum späteren magischen speichern

sys.exit(0) # hm... was steht jetzt in x.dat? Laut Doku entweder 2, oder 1, oder gar nichts...

Im Übrigen ist es sogar möglich, dass beide Objekte rechtzeitig gelöscht und ihre Werte nach x.dat geschrieben wurden, aber so, dass am Ende dort der Wert 1 steht. Warum, fragst du? Weil der garbage collector nicht gezwungen ist, irgendeine deterministische Reihenfolge beim Löschen von Objekten einzuhalten. Und sollte folgendes irgendwo in deinem code auftauchen:

Code: Alles auswählen

import gc
gc.disable()
dann wird niemals irgendeine __del__-Methode aufgerufen. Und wenn es komplizierte zirkuläre Referenzen zwischen Objekten gibt, werden diese, selbst bei angeschaltetem garbage collector, niemals gelöscht, sondern werden zum memory leak. Auch da wird dann __del__() nie aufgerufen.

Deswegen empfehle ich, im Anschluss an cofi und lunar, es mal mit logging zu versuchen.

Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
lunar
Python-Forum Veteran
Beiträge: 5748
Registriert: Freitag 4. August 2006, 11:29

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon lunar » Sonntag 15. Mai 2011, 20:49

Wie Du "store_var" umsetzen kannst, musst Du schon selbst wissen, nur Du weißt schließlich, was genau Du wohin speichern möchtest. Da Du das auch nicht verraten hast, könnten wir nur raten, und das wäre dann wirklich unproduktiv.

Die Warnung, dass ".__del__()" nicht aufgerufen wird, ist im Übrigen auch ernst zu nehmen, gerade bei Deinem Vorhaben. Beendet sich der Interpreter aufgrund einer Ausnahme, wie es ja im Fehlerfall wahrscheinlich ist, so sind unter Umständen noch ziemlich viele Objekte referenziert, da der Traceback der Ausnahme Referenzen auch lokale Namen in den betroffenen Funktionen halten kann. Im Zweifelsfall wird ".__del__()" dann für genau die Objekte, an denen Du interessiert bist, weil sie den Fehler verursacht haben, nicht aufgerufen.

Eine andere Möglichkeit wäre "sys.set_trace()". Dort könntest Du beispielsweise beim Verlassen jeder Funktion alle lokalen Namen sichern. Der Preis ist, dass das Programm wesentlich langsamer läuft. Außerdem arbeitest Du dann immer noch in den Interna, was wiederum neue, schwer zu findende Fehler verursachen kann.

Und das alles wird man Dir, so hoffe ich doch, auch auf StackOverflow sagen.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16021
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon Leonidas » Sonntag 15. Mai 2011, 20:57

Gerenuk hat geschrieben:Hat jemand eine Idee wie man store_var umsetzen könnte? Hmm, ich finde das verwirrend ... aber notwendig ;)

Na, einfach mit ``pickle.dump``. Mehr als Dokumentation lesen und verstehen ist das nicht.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Gerenuk
User
Beiträge: 69
Registriert: Donnerstag 21. Januar 2010, 22:27

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon Gerenuk » Sonntag 15. Mai 2011, 22:42

pillmuncher hat geschrieben:Das, was du vorhast, wird nicht funktionieren. In der Doku zu object.__del__() steht "Called when the instance is about to be destroyed. [...] It is not guaranteed that __del__() methods are called for objects that still exist when the interpreter exits." oder auf deutsch: wenn ein Objekt zerstört wird, wird __del__ aufgerufen, außer es wird nicht aufgerufen.

Na mit etwas mehr Kreativität und weniger Schwarzmalerei geht das doch bestimmt?! Ich meine du nennst den GC ja selbst und bestimmt hat der manuelle Collect?
Wieso wird versucht es hier kaputt zureden, anstatt einfach zu sagen wie man die Klasse von einem existierenden Objekt ändern kann, so dass sie eine neue __del__ Methode hat? Entweder man weiß es oder eben nicht. Ein "Ich weiß es nicht, aber das ist eh scheiße" bringt mich nicht weiter.

Zum Glück hat Boaz auf Stackoverflow die Frage verstanden. Bleibt nur die Frage ob man das noch abrunden kann, damit alles passt. Aber so bin ich schonmal weiter.
Benutzeravatar
pillmuncher
User
Beiträge: 985
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon pillmuncher » Sonntag 15. Mai 2011, 23:13

@Gerenuk: Ich habe nicht geschrieben, dass ich nicht weiß, wie man __del__ an ein Objekt, im Gegensatz zu dessen Klasse, binden kann, so dass der garbage collector das mitbekommt. Statt dessen habe ich geschrieben, dass ich weiß, dass es nicht geht. Nur nicht so explizit, sondern in Form zweier Links auf die Dokumentation, wo genau steht, wie special methods implizit aufgerufen werden, und dass ein Aufruf von __del__ niemals garantiert ist. Das hat nichts mit Schwarzseherei zu tun, sondern mit schlichter Rationalität. Und was Kreativität anbelangt, da schlage ich vor, diese darauf zu verwenden, eine Lösung zu erfinden, die funktioniert, und nicht eine, die mehr Probleme mit sich bringt, als sie löst.

Um Jamie Zawinski zu paraphrasieren: Some people, when confronted with a problem, think "I know, I'll use object.__del__()." Now they have two problems.
In specifications, Murphy's Law supersedes Ohm's.
Gerenuk
User
Beiträge: 69
Registriert: Donnerstag 21. Januar 2010, 22:27

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon Gerenuk » Sonntag 15. Mai 2011, 23:26

pillmuncher hat geschrieben: Das hat nichts mit Schwarzseherei zu tun, sondern mit schlichter Rationalität. Und was Kreativität anbelangt, da schlage ich vor, diese darauf zu verwenden, eine Lösung zu erfinden, die funktioniert, und nicht eine, die mehr Probleme mit sich bringt, als sie löst.

Darauf habe ich doch gerade geantwortet. Kann man am Ende des Programmes den GC explizit anweisen alles zu löschen oder nicht? Soll ich selbst nachschauen? Ich vermute es geht und es wäre nur ein Befehl. Das meine ich mit Schwarzmalerei.
Und selbst im schlimmsten Fall sind ein paar unvollständige Debug Infos besser als gar keine.
Benutzeravatar
pillmuncher
User
Beiträge: 985
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon pillmuncher » Montag 16. Mai 2011, 00:06

Gerenuk hat geschrieben:Kann man am Ende des Programmes den GC explizit anweisen alles zu löschen oder nicht? Soll ich selbst nachschauen?

Du hast recht, das wäre geradezu eine Zumutung.

Gerenuk hat geschrieben:Ich vermute es geht und es wäre nur ein Befehl. Das meine ich mit Schwarzmalerei.
Und selbst im schlimmsten Fall sind ein paar unvollständige Debug Infos besser als gar keine.

Klar kannst du das selber aufrufen. Aber auch dann ist nicht garantiert, dass der gc alles aufräumt. Was, wenn dein Programm vorher abschmiert? oder wenn es zirkuläre Referenzen gibt? Und wie ich schon geschrieben habe, werden die Werte nicht in der selben Reihenfolge gespeichert, wie die Variablen, deren Werte sie sind, out of scope gehen, sondern der gc löscht die Objekte in der Reihenfolge, die ihm gerade in den Kram passt. Nochmal:

Code: Alles auswählen

x = MyObjectWithDel(1)
x = MyObjectWithDel(2)
x = MyObjectWithDel(3)
del x
gc.collect()
Selbst wenn wir davon ausgehen, dass der gc alle drei Objekte löscht und ordentlich __del__() auf ihnen aufruft, er wird sie in irgendeiner Reihenfolge löschen, zB. 2, 3, 1, und dann steht in deiner Debug Datei nicht ein unvollständiger Wert, sondern ein falscher. Viel Spass beim Debuggen der Debug Infos.

Des Weiteren: Du scheinst zu glauben, dass del x das Objekt löscht, oder als gelöscht markiert. Das tut es natürlich nicht. Es löscht nur den Namen 'x' aus dem Namespace und dekrementiert den ref counter des Objekts. Angenommen folgender Code:

Code: Alles auswählen

x = MyObjectWithDel(1)
some_object.some_method(x)
del x
Für's folgende: Sei V eine Variable, dann sei |V| das Objekt, auf das V verweist.

Dann kann es sein, dass |some_object| noch eine Referenz auf das ursprüngliche Objekt |x| hält, und dann wird |x| erst gelöscht werden, nachdem |some_object| gelöscht wurde. Natürlich vorausgesetzt, dass |some_object| nicht auch wieder von irgendwo her referenziert wird, etc. pp. ad nauseam. Am Ende wirst du dann jede Variable in deinem Programm händisch del'en müssen, und voila, willkommen in der C++-Welt. Python ist nicht C++, und vieles, was in C++ sinnvoll oder sogar notwendig ist, ist in Python unnötig, unsinnig und schädlich.

Und jetzt komm nicht wieder mit Schwarzseherei. Wenn Sachen nicht funktionieren, dann wird keine rosa Brille sie zum funktionieren bringen. Das war früher anders, als das Wünschen noch geholfen hat.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pillmuncher
User
Beiträge: 985
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Re: Variablen automatisch sichern / Löschmethode überschreib

Beitragvon pillmuncher » Montag 16. Mai 2011, 00:53

Zum Spaß:

Code: Alles auswählen

>>> class T(object):
...     def __init__(self, v):
...         self.v = v
...     def __del__(self):
...         print self.v
...
>>> m = map(T, range(3))
>>> for i in m:
...     pass
...
>>> del m
1
0
>>> del i
2
>>> m = map(T, range(3))
>>> for i in m:
...     pass
...
>>> del i
>>> del m
2
1
0
>>> import gc
>>> x = T(None)
>>> y = T(x)
>>> x.v = y
>>> del x
>>> del y
>>> gc.collect()
0
>>> gc.garbage
[]
>>> z = T('reachable')
>>> [o for o in gc.get_objects() if isinstance(o, T)]
[<__main__.T object at 0x7ff4a08c>, <__main__.T object at 0x7ff4a1cc>, <__main__.T object at 0x7ff4a38c>]
In der Doku zu gc.collect() steht: With no arguments, run a full collection. [...] The number of unreachable objects found is returned.
In der Doku zu gc.garbage steht: A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects). By default, this list contains only objects with __del__() methods.
In der Doku zu gc.get_objects() steht: Returns a list of all objects tracked by the collector

Zwei der Objekte, die von gc.get_objects() zurückgegeben werden, sind also unreachable, werden aber vom garbage collector als solche nicht erkannt. Interessant.
In specifications, Murphy's Law supersedes Ohm's.

Zurück zu „Allgemeine Fragen“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder