Es kracht bei Objektzerstörung - wieso?

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
dennis.py

Und direkt die zweite Frage:

Im Buch ist folgender Code samt Ausgabe gegeben, und wenn ich den Code ausführe, funktioniert auch alles:

Code: Alles auswählen

#!/usr/bin/python

class Person:
	'''Stellt eine Person dar.'''
	bevoelkerung = 0

	def __init__(self, name):
		'''Initialisiert die Daten der Person.'''
		self.name = name
		print '(Initialisiere %s)' % self.name

		# Wenn diese Person erzeugt wird,
		# traegt er/sie zur Bevoelkerung bei
		Person.bevoelkerung += 1

	def __del__(self):
		'''Ich sterbe.'''
		print '%s verabschiedet sich.' % self.name

		Person.bevoelkerung -= 1

		if Person.bevoelkerung == 0:
			print 'Ich bin der letzte.'
		else:
			print 'Es gibt noch %d Leute.' % Person.bevoelkerung

	def sagHallo(self):
		'''Begruessung durch die Person.

		Das ist wirklich alles, was hier geschieht.'''
		print 'Hallo, mein Name ist %s.' % self.name

	def wieViele(self):
		'''Gibt die aktuelle Bevoelkerungszahl aus.'''
		if Person.bevoelkerung == 1:
			print 'Ich bin ganz allein hier.'
		else:
			print 'Es gibt hier %d Leute.' % Person.bevoelkerung

swaroop = Person('Swaroop')
swaroop.sagHallo()
swaroop.wieViele()

kalam = Person('Abdul Kalam')
kalam.sagHallo()
kalam.wieViele()

swaroop.sagHallo()
swaroop.wieViele()

Code: Alles auswählen

(Initialisiere Swaroop)
Hallo, mein Name ist Swaroop.
Ich bin ganz allein hier.
(Initialisiere Abdul Kalam)
Hallo, mein Name ist Abdul Kalam.
Es gibt hier 2 Leute.
Hallo, mein Name ist Swaroop.
Es gibt hier 2 Leute.
Abdul Kalam verabschiedet sich.
Es gibt noch 1 Leute.
Swaroop verabschiedet sich.
Ich bin der letzte.
Ich habe dann meine eigene Fassung etwas verändert:

Code: Alles auswählen

#!/usr/bin/python
#-*- coding: utf-8 -*-

class Person:
    bevoelkerung = 0

    def __init__(self, name):
        self.name = name
        print "Initialisiere %s..." % self.name
        Person.bevoelkerung += 1

    def __del__(self):
        print "%s stirbt." % self.name
        Person.bevoelkerung -= 1
        if Person.bevoelkerung == 0:
            print "Ich war der letzte."
        else:
            print "Es gibt aber noch %d andere." % Person.bevoelkerung

    def sagHallo(self):
        print "Hallo, mein Name ist %s." % self.name

    def wieViele(self):
        if Person.bevoelkerung == 1:
            print "Ich bin ganz allein hier."
        else:
            print "Es gibt hier %d Personen." % Person.bevoelkerung


dennis = Person("Dennis")
dennis.sagHallo()
dennis.wieViele()

kalam = Person("Kalam")
kalam.sagHallo()
kalam.wieViele()

dennis.sagHallo()
dennis.wieViele()
Dabei fliegt eine Exception, aber ich sehe den Fehler nicht:

Code: Alles auswählen

Initialisiere Dennis...
Hallo, mein Name ist Dennis.
Ich bin ganz allein hier.
Initialisiere Kalam...
Hallo, mein Name ist Kalam.
Es gibt hier 2 Personen.
Hallo, mein Name ist Dennis.
Es gibt hier 2 Personen.
Kalam stirbt.
Es gibt aber noch 1 andere.
Dennis stirbt.
Exception AttributeError: "'NoneType' object has no attribute 'bevoelkerung'" in <bound method Person.__del__ of <__main__.Person instance at 0x2652c68>> ignored
BlackJack

@dennis.py: Lies bitte die Warnung in der Python-Dokumentation zu `__del__`. Und implementiere die Methode dann nie wieder. Es ist weder garantiert wann die Methode aufgerufen wird, noch ob sie *überhaupt* jemals aufgerufen wird. Und wenn sie aufgerufen wird, darfst Du im Grunde von so gut wie nichts ausgehen was sich ausserhalb des Objekts befindet, auf dem sie aufgerufen wird.

Wenn zum Beispiel der Interpreter gerade "runterfährt", könnte im schlimmsten Fall sogar ein einfaches ``print`` auf die Nase fallen, wenn das `sys.stdout`-Objekt vorher schon zerstört wurde. In Deinem Falle wurde das Klassenobjekt `Person` schon zerstört oder zumindest das Attribut im Modul durch `None` ersetzt, bevor die `__del__`-Methode aufgerufen wurde.
dennis.py

Dann verstehe ich aber nicht, wieso das Beispiel aus dem Buch ohne Murren funktioniert. Oder ist das reiner Zufall? An der Logik habe, meiner Meinung nach, nichts wesentliches verändert... oder doch?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das Beispiel aus dem Buch funktioniert mehr oder weniger aus Zufall.

Die Exception tritt bei dir durch den Zugriff auf ``self.name`` in `__del__` auf. `__del__` wird erst aufgerufen nachdem Attribute die nicht mit _ beginnen schon gelöscht wurden, zumindest fast immer und wenn `__del__` überhaupt aufgerufen wird.

Prinzipiell solltest du `__del__` ignorieren, es gibt nur ganz wenige Fälle in denen es Sinn macht es zu verwenden, solange du dir nicht sicher bist dass du einen solchen Fall gefunden hast, solltest du `__del__` weiter ignorieren.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Bei mir kommt derselbe Fehler wie bei dir. Wenn ich allerdings folgendes mache:

Code: Alles auswählen

swaroop = Person("Dennis")
swaroop.sagHallo()
swaroop.wieViele()

kalam = Person("Kalam")
kalam.sagHallo()
kalam.wieViele()

swaroop.sagHallo()
swaroop.wieViele()
kommt kein Fehler. Es ist also tatsächlich Zufall. Im Übrigen schließe ich mich BlackJack an.

Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
Antworten