Klasse zuverlässig löschen

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
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Hi, ich lasse gerade ein Tool laufen, das Dateien aus dem Netz herunterlädt und habe dabei das Problem, dass die Klasse wohl nicht zuverlässig gelöscht wird und beim nächsten Mal noch auf URLs aus dem vorherigen Durchlauf zugreift.

Code: Alles auswählen

downloader = downloadTool(url)
downloader.start()
del downloader
Die url bezieht das Tool in meiner Software aus einer Schleife, d. h. es wird jeweils eine andere URL an den Schleifenblock übergeben.

Meine Frage ist jetzt, was ich ggf. falsch mache bzw. wie das Problem entsteht!? Ich hätte gedacht, dass ein neues Objekt von der Klasse auch ein ganz neues Objekt erzeugt. Ich konnte aber feststellen, dass bestimmte Eigenschaften vorbelegt bleiben. In der init-Methode habe ich das jetzt so gelöst, dass ich die Variable tatsächlich neu erzeuge, die noch Sachen vom letzten Durchlauf enthielt.

Ich hätte erwartet, dass zumindest das del alles von der Software zuverlässig löscht!? Muss ich da bei __del__ in der Klasse was machen!? Dachte, dass dort hinterlegter Code nur zur Ausführung gelangt, wenn die Klasse gerade gelöscht wird!?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@pixewakb: 'del' löscht keine Objekte sondern nur den Namen aus dem aktuellen Namensraum. Wenn man aber nicht sauber programmiert und irgendwo globale Zustände erzeugt, können die auch bei neuen Objekten irgendwie reinspuken. Zeig doch mal den Code von downloadTool.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Da ist ziemlich viel fremer Code verbaut (keine "freie" Lizenz - ist/war von einer Tutorialseite), hat dafür aber ganz wunderbar gearbeitet. Blöde Frage: Gibt es eine zuverlässige Möglichkeit ein Objekt sicher und vollständig zu löschen? Ich habe es schon mittel downloader = None versucht, war aber auch nicht so erfolgreich...
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@pixewakb
Wofür benötigst Du das ``downloadTool``? Lässt sich doch eventuell auch mit Bordmitteln bewerkstelligen...?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@pixewakb: Ich weiss nicht wie Du Dir das vorstellst. Mal angenommen man *könnte* ein Objekt explizit löschen, dann würde Dein Programm doch an der Stelle wo der alte Wert verwendet wird, auf die Fresse fallen weil dort dann versucht wird auf ein Objekt zuzugreifen das nicht mehr existiert. Damit wäre doch nichts gewonnen.

Man kann Objekte aber nicht explizit löschen in Python. Ein Objekt kann dann gelöscht werden wenn es vom Code nicht mehr erreichbar ist. *In* der `__del__()`-Methode kann man nichts machen *das* das Objekt gelöscht wird, sondern es ist umgehkerht: die Methode wird aufgerufen wenn das Objekt gelöscht werden soll. Wobei das nicht garantiert ist das ein Objekt überhaupt gelöscht wird, *und* das alleinige *vorhandensein* einer `__del__()`-Methode kann sogar mit ein Grund sein warum ein Objekt *nicht* gelöscht wird, auch wenn es vom Code gar nicht mehr erreicht werden kann. Von `__del__()` sollte man dringend die Finger lassen solange man die Konsequenzen davon nicht übersieht. Man braucht diese Methode auch nicht solange man nicht externe Ressourcen verwalten muss von denen die Speicherverwaltung von Python nichts weiss.

Ein ``del`` auf einen einfachen Namen angewendet ist in aller Regel ein Zeichen das man etwas komisches macht. Das ist nur sehr selten sinnvoll und zwar dann wenn man tatsächlich einen *Namen* löschen möchte.

Da Du keinen Quelltext zeigen möchtest, kann man ja nur noch fröhlich raten. Benutzt Du vielleicht irgendwo veränderbare Objekte als Defaultwerte bei Funktionen oder Methoden? Also so etwas wie ``def function(parrots=[]):``.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Zum Tool: Um mal für etwas Klarheit zu sorgen - Die Grundfunktion des Tools besteht ich denke aus den unten eingefügten Zeilen, d. h. für eine URL zu einer Datei wird der Download dieser Datei erledigt, was man auch mit dem request-Modul machen könnte, aber ich hatte irgendwoher ein anderes sniplet. Das Tool selbst ist größer, weil es für die URL zu einer HTML-Seite alle dort verlinkten PDF-Dateien erfasst, die Datei-URLs ausliest, einen Ordner auf der Platte anlegt, dort die Dateien reinspeichert und dabei noch den Dateinamen anpasst. Hat heute funktioniert und eine sehr, sehr große Menge an PDF-Dateien (> 1.000) gespeichert. Das Tool hat einige Zeit - mit Aussetzern - gearbeitet. (Mehr ins Detail gehen möchte ich da bei der Quelle und den Dateien nicht - ich bin mir nicht sicher, ob der Webseitenbetreiber mit dieser Art des Zugriffes gerechnet hat; robots.txt ist OK und die Website ist öffentlich zugänglich und auf Hochlast getrimmt, wenn ich das als Laie beurteilen kann.)

Zum Quellcode: Ich habe mir gerade noch mal die Importe angesehen und ich kann definitiv ausschließen, dass größere Teile des Tools von mir stammen, ich kann aber auch nicht mehr sagen, von wo ich es geklaut oder anders gesagt zusammengestückelt habe. Einige der Methoden sind komplett fremder Code; die "Verbindungen" lesen sich mehr nach meinem Programmierstil, d. h. einfach und wenig elegant.

U. a. sind da solche Sachen im Quellcode (und zusätzlich einiges mit dem re-Modul):

Code: Alles auswählen

                with urllib.request.urlopen(url) as response, open(dateiname, 'wb') as out_file:
                    shutil.copyfileobj(response, out_file)
Vielleicht von da. Beim Rest kriege ich das nicht mehr zusammen.

@BlackJack: Die Erklärung hat mir weitergeholfen, ich hatte das mit garbage collection unter Python nicht bewusst auf dem Schirm und hatte heute dann eine Änderung vorgenommen, die das Problem löste (im Konstruktor). Ich denke, dass ich die Software mal bei Gelegenheit neu schreibe.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Das sorgt nicht für Klarheit.

Damit wir wissen was passiert, brauchen wir die von dir angesprochene Schleife, in der das hier passiert:

Code: Alles auswählen

downloader = downloadTool(url)
downloader.start()
del downloader
Außerdem das was downloadTool ist.
Eine Klasse? Wenn Ja hast du dich nicht an die Konventionen der Namensgebung gehalten.

Wenn das eine Klasse ist:
wir brauchen die Struktur. Also alles, das was in der ersten und zweiten Einrückungsebene steht. den Rest kannst du löschen.

Code: Alles auswählen

class dowloadTool():
    variable = irgendwas
    def __init__(self):
    def start(self):
    ....
Und kopier das bitte aus deinem Quelltext, nicht nach Gutdünken zusammenbasteln. Ich befürchte du machst da seltsame machen mit Variablen in der Klasse und/oder überschreibst die global.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Ich habe mal da ein sehr einfaches OO-Tool von mir reinkopiert, wo ich mir sicher bin, dass es häftig Kritik hagelt, ich aber keine Probleme mit dem Urheberrecht oder ... bekommen kann. Ich bitte um Verständnis.
BlackJack

@pixewakb: Hauptkritik dort ist das die Klasse fehlerhaft ist und das ganze mit einer Liste und einer Funktion hätte abgefrühstückt werden können.
Antworten