Seite 1 von 1

Zwei Verständnisfragen zu Klassen

Verfasst: Mittwoch 22. August 2007, 12:56
von Koppaz
Hallo, ich versuch gerade Python zu lernen (meine erste ernsthafte Programmiersprache), und hab mir zu dem Zweck mal „A Byte of Python“ in der deutschen Fassung als .pdf runtergeladen. Inzwischen bin ich bei Klassen angelangt. Da ich, um zu lernen, das ganze verstehen und hinterschauen muss, hab ich da zwei Verständnisfragen. Hab zwar schon nach ner Erklärung gesucht, aber nichts zufriedenstellendes gefunden.

Am ehesten lassen die sich mit folgendem Code aus „A Byte of Python“ von „Swaroop C H“ (in der deutschen Fassung) erläutern (Gekürzt auf das wichtigste / kompletter Code auf Seite 74/75 des Buchs bzw. 86/87 der PDF):

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
		Person.bevoelkerung += 1
		
	def __del__(self):
		# gekürzt da nicht wichtig

	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):
		# gekürzt da nicht wichtig

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

Daraufhin kommt folgende Ausgabe:
$ python objvar.py
(Initialisiere Swaroop)
Hallo, mein Name ist Swaroop.
# Rest weggekürzt da nicht wichtig
Meine erste Frage bezieht sich auf Klassen- und Objektvariblen.

So weit ich das verstehe gibt es hier die Klasse „Person“ mit den Objekten „__init__“, „__del__“, „sagHallo“ und „wieViele“. Ebenso werden die Klassenvariable „bevoelkerung“ und die Objektvariable „self.name“ (im Objekt „__init__“) definiert (sofern definiert das richtige Wort ist).
Mein Problem: Ich verstehe Klassen- und Objektvariablen wie globale und lokale Variablen (die ich schon beim Thema „Funktionen“ kennen gelernt habe). Warum kann dann die Objektvariable „self.name“, die im Objekt „__init__“ definiert wurde, im Objekt „sagHallo“ abgerufen werden? Soweit ich das verstehe (und ich verstehe das mit Sicherheit falsch) dürfte die im Objekt „sagHallo“ nicht mehr gültig sein. Also was bewirkt das die Variable im entsprechenden Objekt trotzdem abgerufen werden kann? Beziehungsweise was ist dann die Definition von Klassenvariable und Objektvariable, wo ist der Unterschied?
Wird durch das „self.“ davor die Variable doch für die ganze Klasse zugänglich, oder sind Objektvariablen generell für alle Objekte zugänglich, oder hat das was mit dem Objekt „__init__ zu tun, das ja sowiso eine „besondere“ bedeutung hat, oder ist der einzige Unterschied zwischen Klassen- und Objektvariablen wo die Variable defininiert wird und wo sie abgerufen wird?

Jetzt die zweite Frage:

In Zeile 25 wird folgender Code angegeben:

Code: Alles auswählen

swaroop = Person('Swaroop')
Und daraufhin (wenn man den Code Schritt für Schritt ausführen würde) wird direkt folgendes Ausgegeben:
(Initialisiere Swaroop)
Mein Problem hier: Ich sehe „swaroop“ in dem Fall als eine einfache (globale) Variable im Hauptblock, die lediglich dazu dient das man später nur „swaroop“ anstatt „Person('Swaroop')“ eingeben muss. Jedoch wird gleich die Klasse „Person“ (und damit auch gleich das dazugehörige Objekt „__init__“) angesprochen. Also wird der Inhalt der Variable gleich ausgeführt. Das halte ich für merkwürdig. Wenns wirklich eine Variable ist, ist das generell so? Und wenns keine einfache (globale) Variable ist, was ist das dann?
Ganz zu schweigen davon, wenns wirklich so ist wie ich glaube (normale, globale Variable), dann erklärt sich mir der Sinn sowiso nicht, denn wäre es dann nicht besser gleich den Klassennamen/-aufruf zu verwenden, um später nicht erst noch in der Variable nachschauen zu müssen welche Klasse denn nun gemeint ist?

Hat vielleicht jemand nen Denkanstoß in die richtige Richtung? Oder ob mir das vielleicht jemanden in einer „Version für Begriffsstutzige“ erklären kann?

Zum Schluss (ich weis nicht ob von Belang) hier noch diverse, vielleicht hilfreiche, Infos:

OS: WinXP mit SP2
Python: v2.5.1
A Byte of Python: Zeitstempel vom 05.08.2006 / Übersetzung der Version 1.20 vom 13.01.2005
IDE: Stani's Python Editor v0.8.3.c
Code-Ausführung per Eingabeaufforderung

Ich bedanke mich schonmal im voraus für jeden Versuch mir zu Helfen.

Re: Zwei Verständnisfragen zu Klassen

Verfasst: Mittwoch 22. August 2007, 13:34
von penguin-p
Koppaz hat geschrieben: Meine erste Frage bezieht sich auf Klassen- und Objektvariblen.

So weit ich das verstehe gibt es hier die Klasse „Person“ mit den Objekten „__init__“, „__del__“, „sagHallo“ und „wieViele“. Ebenso werden die Klassenvariable „bevoelkerung“ und die Objektvariable „self.name“ (im Objekt „__init__“) definiert (sofern definiert das richtige Wort ist).
Es existieren die Methoden __init__, __del__, sagHallo und wieViele, sowie das statische Attribut bevoelkerung.
Mein Problem: Ich verstehe Klassen- und Objektvariablen wie globale und lokale Variablen (die ich schon beim Thema „Funktionen“ kennen gelernt habe). Warum kann dann die Objektvariable „self.name“, die im Objekt „__init__“ definiert wurde, im Objekt „sagHallo“ abgerufen werden? Soweit ich das verstehe (und ich verstehe das mit Sicherheit falsch) dürfte die im Objekt „sagHallo“ nicht mehr gültig sein. Also was bewirkt das die Variable im entsprechenden Objekt trotzdem abgerufen werden kann? Beziehungsweise was ist dann die Definition von Klassenvariable und Objektvariable, wo ist der Unterschied?
So kannst du das leider nicht sehen. Im Konstruktor __init__ wird ein neues Attribut namens self.name angelegt und der Wert von name zugewiesen. Eine lokale Variable würde ohne das self geschrieben.
Ein Attribut ist eine Variable, die klassenweit zur Verfügung steht. D.h. insbesondere, dass jede Methode der Klasse darauf zugreifen kann, eben über self.name.
Das Beispiel ist aber insofern nicht ganz so optimal, als dass zusätzlich noch der Unterschied zwischen statischen und nicht-statischen Attributen zum Tragen kommt. Person.bevoelkerung ist statisch, das heißt für alle Instanzen der Klasse Person dieselbe Variable. Wenn eine neue Instanz erzeugt wird, kannst du dir das so vorstellen, dass Person.bevoelkerung in allen bestehenden Instanzen auch hochgezählt wird.
self.name ist dagegen ein nicht-statisches Attribut, das heißt es ist für jede Instanz von Person verschieden. Muss es ja auch, denn jede Person hat einen eigenen Namen.

Zur zweiten Frage:

Code: Alles auswählen

swaroop = Person('Swaroop')
Hier wird die Klasse Person instanziiert und die entstehende Instanz der Variablen swaroop zugewiesen. Beim Instanziieren wird der Konstruktor __init__ aufgerufen. In diesem können beispielsweise, wie es im Beispiel auch gemacht wird, alle nicht-statischen Attribute initialisiert werden. Außerdem gibt der Konstruktor in deinem Fall noch eien Meldung auf dem Bildschirm aus.
Nach dem Ausführen des Konstruktors ist die Klasse quasi einsatzbereit und du kannst mit ihr machen was du willst ;)

Hmm, ich hoffe das war nicht allzu schwammig formuliert und dass es dir wenigstens ein bisschen hilft :)

Verfasst: Mittwoch 22. August 2007, 14:17
von Koppaz
„Ein bischen“ ist untertrieben. Das Bild gewinnt an Konturen.

Code: Alles auswählen

swaroop = Person('Swaroop') 
erzeugt also eine Instanz.

Im ursprünglichen Beispiel stand ein paar Zeilen dadrunter noch:

Code: Alles auswählen

kalam = Person('Abdul Kalam') 
was dann Instanz Nummer 2 wäre.

Sofern ich dann in Instanz Nummer 2 das statische Attribut „Person.bevoelkerung“ änder, ändert sich das auch in Instanz 1. Das nicht-statische Attribut „self.name“ ist aber immer nur für die eigene Instanz zuständig (und Klassenweit verfügbar). Wenn ich das also in Instanz 2 änder (oder anlege), ändert sich das in Instanz 1 nicht.

Das ergibt Sinn.

Ich werd mir das mit Instanzen den auf jeden Fall noch mal genauer ansehen.

Danke vielmals, bin ich nun doch ein ganzes Stück weiter, das war genau das was ich Wissen wollte. :)

Verfasst: Mittwoch 22. August 2007, 14:35
von penguin-p
Genau das triffts ... viel Spaß beim ruminstanziieren ;)

Re: Zwei Verständnisfragen zu Klassen

Verfasst: Mittwoch 22. August 2007, 14:47
von Leonidas
Hallo Koppaz, willkommen im Forum,
Koppaz hat geschrieben:Meine erste Frage bezieht sich auf Klassen- und Objektvariblen.
Erster Punkt: in Python gibt es keine Variablen. Das Variablendenken anderer Sprachen führt dazu, dass man viele Dinge die in Python eigentlich ganz simpel zu verstehen sind, falsch im Kopf hat.

In Python gibt es nur Objekte und Namen. Mehr nicht. Ein Objekt kann null, einen oder mehrere Namen haben, ein Name zeigt immer auf ein Objekt.
Koppaz hat geschrieben:So weit ich das verstehe gibt es hier die Klasse „Person“ mit den Objekten „__init__“, „__del__“, „sagHallo“ und „wieViele“.
Und ``__doc__`` und ``__module__``. Findet man mit ``dir(Person)`` heraus.
Koppaz hat geschrieben:Ebenso werden die Klassenvariable „bevoelkerung“ und die Objektvariable „self.name“ (im Objekt „__init__“) definiert (sofern definiert das richtige Wort ist).
So etwas heißt wenn dann Instanzvariable, aber eigentlich müsste es eher "Instanzname" sein.
Koppaz hat geschrieben:Mein Problem: Ich verstehe Klassen- und Objektvariablen wie globale und lokale Variablen (die ich schon beim Thema „Funktionen“ kennen gelernt habe).
Dann verstehst du sie möglicherweise Falsch. Klassenvariablen sind Variablen die für alle Instanzen einer Klasse gleich sind. Instanzvariablen sind Objekte die an die Instanz der Klasse gebunden sind (``self``).
Koppaz hat geschrieben:Warum kann dann die Objektvariable „self.name“, die im Objekt „__init__“ definiert wurde, im Objekt „sagHallo“ abgerufen werden?
``self.name`` ist ein Attribut der Instanz (deswegen auch der Punkt zwischen dem ``self`` und dem ``name``, es wurde in ``__init__`` definiert.
Koppaz hat geschrieben:Soweit ich das verstehe (und ich verstehe das mit Sicherheit falsch) dürfte die im Objekt „sagHallo“ nicht mehr gültig sein. Also was bewirkt das die Variable im entsprechenden Objekt trotzdem abgerufen werden kann?
``sagHallo()`` hat als ersten Parameter ``self``. Damit hat man in ``sagHallo()`` Zugriff auf die Instanz und kann das Attribut ``name`` abfragen.
Koppaz hat geschrieben:Wird durch das „self.“ davor die Variable doch für die ganze Klasse zugänglich,
Nein, nicht direkt. ``self`` ist einfach nur der Name,an den die aktuelle Instanz gebunden wird. Könnte genausogut aber auch ``hans`` lauten - da ist nichts magisches dran, es verhält sich wie Funktionen (und es kommt noch besser, du kannst auch die Klassenmethoden nutzen indem die ihnen als ersten Parameter eine Instanz mitgibst).
Koppaz hat geschrieben:„__init__ zu tun, das ja sowiso eine „besondere“ bedeutung hat
``__init__`` ist einfach der Konstruktor der Klasse. Er wird automatisch aufgerufen, wenn du eine Instanz der Klasse erstellst.
Koppaz hat geschrieben:Mein Problem hier: Ich sehe „swaroop“ in dem Fall als eine einfache (globale) Variable im Hauptblock, die lediglich dazu dient das man später nur „swaroop“ anstatt „Person('Swaroop')“ eingeben muss.
:?: Der String (das Objekt) "swaroop" wird in ``__init__`` nur an den Namen ``self.name`` gebunden. Damit wird der Wert in der Klasseninstanz gespeichert.
Koppaz hat geschrieben:Also wird der Inhalt der Variable gleich ausgeführt. Das halte ich für merkwürdig. Wenns wirklich eine Variable ist, ist das generell so? Und wenns keine einfache (globale) Variable ist, was ist das dann?
:?: Variablen/Namen werden nie ausgeführt, Objekte auch nur wenn man Klammern dahinter setzt. ``"swaroop"()`` ist aber nicht ausführbar.

Verfasst: Mittwoch 22. August 2007, 15:40
von Koppaz
Hallo, danke fürs Willkommen.
In Python gibt es nur Objekte und Namen. Mehr nicht. Ein Objekt kann null, einen oder mehrere Namen haben, ein Name zeigt immer auf ein Objekt.
Also das was ich bisher als "Variable" bezeichnet habe, nennt sich "Name", weis ich bescheid und werd versuchen mich daran zu halten. In "A Byte of Python" war halt auch von Variablen die Rede, sowie von Feldern.
Und ``__doc__`` und ``__module__``. Findet man mit ``dir(Person)`` heraus.
Gut. Ich bezog mich halt auf die explizit genannten. Die beiden gibts natürlich auch.
So etwas heißt wenn dann Instanzvariable, aber eigentlich müsste es eher "Instanzname" sein.
Siehe oben, es war wirklich von "Klassen- und Objektvariablen" die Rede (sogar als Überschrift), aber ich weis ja jetzt bescheid.
``sagHallo()`` hat als ersten Parameter ``self``. Damit hat man in ``sagHallo()`` Zugriff auf die Instanz und kann das Attribut ``name`` abfragen.
Achso, das wusste ich bis jetzt noch nicht, dachte anfänglich das bezieht sich halt nur auf die Methode.
Variablen/Namen werden nie ausgeführt, Objekte auch nur wenn man Klammern dahinter setzt. ``"swaroop"()`` ist aber nicht ausführbar.
Ich bezog mich da auf das Objekt, auf das der Name (swaroop) zeigt, der da war "Person('Swaroop')"


Auch dir danke für die Hilfe

Verfasst: Mittwoch 22. August 2007, 15:49
von Leonidas
Achja, ich habe vergessen das Beispiel von Pythons OOP mitzuliefern:

Code: Alles auswählen

swaroop = Person('swaroop')
Person.sagHallo(swaroop)
Siehst du, hier belegt man ``self`` explizit mit einem Wert.

Achja, ``__del__`` kann man in aller Regel in die Tonne treten, da es sowieso nicht so funktioniert, wie man denken würde.

Verfasst: Mittwoch 22. August 2007, 16:15
von penguin-p
Koppaz hat geschrieben: Also das was ich bisher als "Variable" bezeichnet habe, nennt sich "Name", weis ich bescheid und werd versuchen mich daran zu halten. In "A Byte of Python" war halt auch von Variablen die Rede, sowie von Feldern.
Nicht ganz, Leonidas wollte darauf hinaus, dass du das Variablenkonzept anderer Sprachen, insesondere C/C++, nicht blind auf Python übertragen kannst. In Python ist eine Variable kein Speicherplatz, sondern nur ein Name, der mit einem Objekt verknüpft ist, also eher mit einer Referenz aus C++ vergleichbar. Um das klarzustellen ist es besser statt "Variable" "Name" zu sagen.

Da ich von C++ her komme, übernehme ich manchmal zu viele Begriffe von dort ;). Allerdings ist selbst in der Python Doku gelegentlich von "Variable" die Rede.
Solange du also weißt, was dahinter steckt finde ich den Begriff Variable nicht allzu schlimm.