Seite 1 von 1
Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 11:58
von TrayserCassa
Da ich die Basis von OOP noch nicht so wirklich verstanden haben und es grade versuche habe ich Fragen zu der __init__ Methode. Was ich schon weiß das __init__ ein Konstruktor ist, was das allerdings ist geht über mein Fachwissen hinaus. Allerdings kann ich mir das durch vollgendem Code denken.
Code: Alles auswählen
class Mathe:
def __init__(self):
print("Hallo")
global h
h = 1
global v2
v2 = 2
def rechnung(self):
print("x =", h, " + ", v2)
x = h + v2
print(x)
x = Mathe()
#h = 1
#v2 = 2
x.rechnung()
Ich weiß das dieser Code völlig blödsinnig ist aber mir geht es hier ums Verständnis, denn ich wende ungerne etwas an was ich nicht verstehe
Erste Frage:
Also mit def __init__(self) bewirke ich doch, dass egal welche Methode ich Aufrufe (hier halt rechnung()), immer alles was als __init__ definiert wird, erst ausführe? Oder habe ich das falsch?
Zweite Frage:
was genau bewirkt self? Zitat "Der Parameter self erscheint nur bei der Definition einer Methode. Beim Aufruf wird er nicht angegeben." Das man self einsetzten muss bei einer Methode ist mir bewusst, nur weshalb?
Ich habe auch schon Code gesehen wo Variabel mit self definiert werden.. Beispiel:
Code: Alles auswählen
class Person:
def __init__(self, name):
self.name = name
def sagHallo(self):
print('Hallo, mein Name ist', self.name)
p = Person('Swaroop')
p.sagHallo()
Hier wird doch sozusagen eine globale variabel gesetzt, die dann übergeben wird bei p = Person(variabel)(Also global = nur für diese Klasse) oder?
Es ist nicht so als hätte ich nicht gegoogelt, allerdings für Anfänger die noch nie OOP programmiert haben finde ich Persönlich keine einfach Erklärung. Wohlgemerkt das ich die Destruktor Methode vernachlässigen soll (schon zu oft gelsen aus diesem Forum
). Ich wurde auch schon drauf hingewiesen einfach sachen zu schlucken, bloß brauch ich dieses verständnis, ansonsten kann ich mir Code zusammen ergoogeln und dadurch lerne ich es nicht..
Und hier im Forum kann man auf mich eingehen und ich kann nochmal fragen fals noch etwas Unklar ist, was bei einem Tutorial ehr weniger geht und wenn diese zb. die Destruktor Methode anwenden, dann ist das ja auch nicht im sinne vom richtigen Programmieren. Worauf hier im Forum wert gelegt wird.
Ich bedanke mich schonmal fürs Lesen und vielleicht auch für meine verständnis Fragen.
mfg
Trayser
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 12:26
von Hyperion
Puh... das ist alles so wirr bei Dir, dass Du das am besten wegwirfst und auch Dein Hirn resettest
Hast Du Dir denn mal das
Python-Tutorial durchgelesen und durchgearbeitet?
@1.) Jein. Ein Konstruktor ist es eigentlich nicht, denn Du kannst eine Klasse *ohne* ``__init__``-Methode schreiben und davon natürlich Exemplare erstellen. Andererseits erledigt man in ``__init__`` tatsächlich viele Dinge, die man in anderen Sprachen im Konstruktor tun würde. Wie der Name sagt, passieren darin *Initialisierungen*; du kannst und solltest darin alle Objekt-Variablen (die Dinger mit dem ``self.`` vorne dran) initialisieren.
@2.) wird im offiziellen Tutorial erklärt. ``self`` ist lediglich ein Name für das Exemplar-Objekt, welches der Methode übergeben wird. Du kannst es auch ``albernes_objekt_dings`` nennen, für das Funktionieren eines Python-Programms spielt es keine Rolle. Stell Dir einfach vor, dass eine Methode tatsächlich nur einmal im Speicher existiert, es aber zig verschiedene Exemplare einer Klasse geben kann. Damit eine Methode bei der Ausführung nun weiß, auf welchem Exemplar sie arbeitet, muss sie dieses übergeben bekommen. Das muss der Programmierer natürlich nicht händisch tun, sondern Python selber ermittelt das richtige Objekt und fügt es dem Aufruf automatisch hinzu.
Bei Deinem Beispiel wird intern in etwa folgendes gemacht:
Code: Alles auswählen
p = Person('Swaroop')
p.sagHallo()
# -> Person.sagHallo(p)
Das kannst Du auch testen:
Code: Alles auswählen
class Person:
def __init__(self, name):
self.name = name
def hello(self):
print("hello, ", self.name)
p = Person("Hyperion")
other = Person("TrayserCassa")
p.hello()
> hello, Hyperion
Person.hello()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-13c387e99f03> in <module>()
----> 1 Person.hello()
TypeError: hello() missing 1 required positional argument: 'self'
Person.hello(other)
> hello, TrayserCassa
Person.hello(p)
>hello, Hyperion
Durch das idR. *implizit* übergebene Exemplar-Objekt weiß die Methode, auf welche zugehörigen Werte sie zugreifen muss. Denn die Attribute werden tatsächlich für jedes Exemplar einer Klasse separat gespeichert.
So, und nun kommen bestimmt die Koryphäen und korrigieren mich...
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 12:28
von Leonidas
``__init__`` ist kein Konstruktor, sondern eher ein "Initialisierer" wie man aus dem Namen vielleicht erkennen kann. Nachdem eine Instanz der Klasse erstellt wird, also in deinen Beispielen ``x`` oder ``p`` wird diese Methode automatisch von Python einmal aufgerufen um eben den Zustand zu initialisieren, quasi als würde man ``x.__init__(name)`` aufrufen.
Wozu man das ``self`` braucht: man braucht ja innerhalb der Methode eine Möglichkeit auf die aktuelle Instanz zuzugreifen. Etwa in ``sagHallo`` benötigst du ja eine Referenz auf ``p`` um dort das Attribut ``name`` zu erreichen. Genau so eine Referenz bietet dir ``self`` und es wird automatisch übergeben wenn du ``p.sagHallo()`` aufrufst (was äquivalent zu ``Person.sagHallo(p)`` ist, wo du siehst dass ``p`` als erster Parameter übergeben wird).
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 13:12
von TrayserCassa
@Hyperion:
Hast Du Dir denn mal das Python-Tutorial durchgelesen und durchgearbeitet?
Meine Englisch Kenntnisse sind genauso gut, wie meine Deutsch Kenntnisse
zu 1:
Ok also benutzt man die ``__init__`` Methode, um die Methoden innerhalb einer Klasse mit Variabel zu versorgen
zu 2:
Hmm also wird ``self`` als zuweiser für Methoden aber auch Variabeln genutzt, damit sie weiß welcher Klasse (Exemplar?) sie zugehöhren?
ok moment.. ich glaub ein wenig hab ich das verstanden
Mit dem Aufruf p = Person("Hyperion")
speicherst du "Hyperion" als Variabel im gesamten Klassen raum, sprich für alle Methoden und kannst dann mit p die variabel self.name an alle Methoden übergeben? (Hab ich das so richtig erklärt?
) Beispiel was aber ein Taberror auswirft :K
Code: Alles auswählen
class Person:
def __init__(self, name, name2):
self.name2 = name2
self.name = name
def hello(self):
print("hello, ", self.name)
def greet(self):
print("gruß zurück von", self.name2)
p = Person("Hyperion", "TrayserCassa")
p.hello()
p.greet()
-------------------------------------------
File "test.py", line 9
def greet(self):
^
TabError: inconsistent use of tabs and spaces in indentation
Ok komisch.. Im Editor (Genay Portabel) sind die Methoden untereinander hier werden die aber versetzt Angezeigt
Aber würde das so gehen?
Erstmal danke für die Hilfe und die Mühen
hat mir schonmal weitergeholfen, als die Tutorials die Google ausspucken
@Leonidas
Ok ich kann es zwar nicht mit meinen eigenen Worten ausdrücken, aber ich glaube ich hab es verstanden
Das ist der Punkt wo es mehr oder weniger Klick macht
``p.sagHallo()`` was äquivalent zu ``Person.sagHallo(p)``
Auch danke für deine Hilfe und die Mühen
Edit:
Kommt davon wenn man Code kopiert
der Funktioniert:
Code: Alles auswählen
class Person:
def __init__(self, name, name2):
self.name2 = name2
self.name = name
def hello(self):
print("hello, ", self.name)
def greet(self):
print("gruß zurück von", self.name2)
p = Person("Hyperion", "TrayserCassa")
p.hello()
p.greet()
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 13:29
von /me
TrayserCassa hat geschrieben:Mit dem Aufruf p = Person("Hyperion")
speicherst du "Hyperion" als Variabel im gesamten Klassen raum, sprich für alle Methoden und kannst dann mit p die variabel self.name an alle Methoden übergeben?
Nicht ganz. Durch die Zuweisung in __init__ wird der Wert an ein spezielles Exemplar (Instanz) der Klasse gebunden, nicht an die Klasse selber.
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 13:47
von TrayserCassa
/me hat geschrieben:
Nicht ganz. Durch die Zuweisung in __init__ wird der Wert an ein spezielles Exemplar (Instanz) der Klasse gebunden, nicht an die Klasse selber.
Ok ich glaub die Funktion hab ich Begriffen
Danke für die korrekte Formulierung
mfg Trayser
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 14:43
von /me
TrayserCassa hat geschrieben:Ok ich glaub die Funktion hab ich Begriffen
Dann demonstrieren wir noch mal kurz den Unterschied zwischen Klassenattributen und Instanzattributen.
first_names ist hier auf Klassenebene deklariert. Wenn dann beim Zugriff der Name nicht in der Instanz gefunden wird, dann wird in der Klasse nachgeschaut ob es ihn gibt.
Code: Alles auswählen
>>> class Thing(object):
first_names = ['Eric']
def __init__(self):
self.last_names = ['Idle']
>>> x = Thing()
>>> x.first_names.append('Terry')
>>> x.last_names.append('Jones')
>>> x.first_names
['Eric', 'Terry']
>>> x.last_names
['Idle', 'Jones']
>>> y = Thing()
>>> y.first_names
['Eric', 'Terry']
>>> y.last_names
['Idle']
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 17:36
von TrayserCassa
@ /me
Ok verstanden
dann Frage ich mich allerdings warum man eine Instanz macht und nicht gleich auf Klassenebene. Da muss ja noch ein entscheidener unterscheid sein
Danke für den Code, den speicher ich mir erstmal ab
mfg
Trayser
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Freitag 3. Januar 2014, 17:52
von EyDu
TrayserCassa hat geschrieben:dann Frage ich mich allerdings warum man eine Instanz macht und nicht gleich auf Klassenebene. Da muss ja noch ein entscheidener unterscheid sein
Instanzen/Exemplare sind Ausprägungen einer Klasse. Stelle dir das einfach an einem konkreten Beispiel vor: Du hast eine Auto-Klasse, welche die möglichen Eigenschaften eines Autos beschreibt: PS, Gewicht, Farbe, etc.
Code: Alles auswählen
class Auto(object):
def __init__(self, ps, gewicht, farbe):
self.ps = ps
self.gewicht = gewicht
self.farbe = farbe
Aber natürlich gibt es nicht nur ein Auto, sonder jede Menge verschiedene. Für die verschiedenen Fahrzeuge erstellst du dann eine Instanz der Auto-Klasse:
Code: Alles auswählen
dein_auto = Auto(42, 1000, "rot")
mein_auto = Auto(100, 800, "blau")
Nun existieren zwei verschiedene Fahrzeuge. Änderst du nun etwas ein deinem Auto, dann hat das keine Auswirkung auf meins.
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Samstag 4. Januar 2014, 17:10
von TrayserCassa
@EyDu
Ok jetzt hab ich es begriffen
Viel Dank an alle. Das war mehr wert als ein Tutorial
mfg
Trayser
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Samstag 4. Januar 2014, 18:39
von neovanmatix
Hi,
ich beschäftige mich seit einigen Stunden mit Python und habe noch ein paar Tutorial-Tabs offen. Vielleicht hilft dir der hier weiter?
http://www.python-kurs.eu/python3_klassen.php
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Samstag 4. Januar 2014, 19:09
von BlackJack
Mit der Beschreibung von `__del__()` habe ich immer noch ein wenig Bauchschmerzen. Das ``del`` nur dann `__del__()` startet wenn… ist immer noch irreführend. ``del`` und `__del__()` haben nur sehr entfernt miteinander zu tun. ``del`` löscht Namen aus Namensräumen oder führt zum Aufruf einer Methode auf einem Objekt (*nicht* `__del__()`!) und irgendwo könnte in der Folge davon ein Objekt freigegeben werden, muss es aber nicht, weil das eben nicht hauptsächlich von dem ``del`` abhängt, sondern ob es noch referenzen gibt. IMHO sollte man `__del__()` in Anfänger-Tutorials überhaupt nicht erwähnen, oder nur als „*implementiere das nicht!*”. Oder man versieht das mit einer Warnung die mindestens so stark ist wie die in der Python-Dokumentation. Und immer noch mit dem Hinweis das man die Methode nur in äussersten Spezialfällen braucht und auch dann gut wissen sollte welche Folgen das haben kann.
Datenkapselung präsentiert doppelte führende Unterstriche als „private”, was nicht stimmt. Dazu ist der Mechanismus nicht gedacht und „unsichtbar” und von aussen nicht benutzbar sind die Attribute auch nicht, man kann sie sowohl sehen, als auch darauf zugreifen, sie heissen nur anders. Dieses Name-Mangling ist aber dokumentiert und kein Implementierungsdetail. Nicht-öffentliche Attribute werden einfach mit einem einzelnen führenden Unterstrich gekennzeichnet.
Der `object_zaehler` unter „Statische Member” (sollte in Python-Lingo eigentlich „Klassenattribute” heissen, Member ist ehr C++) hat wegen `__del__()` so seine Problemchen. Und auch wenn das Thema Vererbung erst danach kommt: Die scheinbar schlaue Implementierung mit `type()` richtet lustiges Chaos an wenn man Unterklassen bildet und da nicht auch das Klassenattribut `objekt_zaehler` explizit definiert. Das erste Exemplar von einer Unterklasse startet dann nämlich nicht zwingend bei 0 sondern mit dem Zählerstand der Basisklasse plus eins.
Das Beispiel in „Vererbung” ist semantisch schlecht, denn mit Vererbung werden „ist-ein(e)”-Beziehungen modelliert. Und ein Konto *ist* kein (Konto)zähler. Überhaupt sind Klassenattribute jenseits von Konstanten total selten, weil das globaler Zustand und damit in aller Regel unsauber ist. Wie man so etwas als erstes Beispiel für Vererbung hernehmen kann ist mir ein Rätsel.
Bei „Mehrfachvererbung” bricht es dann recht abrupt ab. Hier hätten noch erwähnt werden sollen, dass man das sehr selten nutzt, weil das diverse Probleme mit sich bringt, vielleicht auch mit Beispielen für selbige. *Wenn* es benutzt wird, dann meistens für „Mix-in”-Klassen. Und hier hätten dann auch die doppelten führenden Unterstriche hingegehört.
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Mittwoch 7. Februar 2018, 21:57
von tholle
Hi Leute,
ich beschaeftige mich nun mit dem Thema seit mehreren Tagen. Immer wenn ich das Gefuehl habe, ich habe das Instanzieren, bzw. Initialisieren verstanden, faellt bei dem einen oder anderen Beispiel meine Vorstellung von Verstaendnis wie ein Kartenhaus in sich zusammen.
Explizit geht's mir um die Frage, warum man eine Instanzierung ueberhaupt braucht. :K
Wenn ich von einem Objekt zwei verschiende Instanzen erschaffe, z.B. InstanzA und InstanzB und Attribute in der Klasse (ohne __init__) anliege, die ich beim Instanzieren veraendere, hat das keine Auswirkung auf die jeweiligen Attribute der beiden Instanzen.
Beispiel (ich konzentrieren mich mal nur an dem Attribut
breite):
Code: Alles auswählen
[class Kiste:
breite = 0
hoehe = 0
tiefe = 0
def getVolumen(self):
vol = self.breite*self.hoehe*self.tiefe
return vol
// InstanzA
meinekiste = Kiste()
meinekiste.breite = 5
meinekiste.hoehe = 10
meinekiste.tiefe = 15
print(meinekiste.breite)
//InstanzB
meineneuekiste = Kiste()
meineneuekiste.breite = 25
meineneuekiste.hoehe = 35
meineneuekiste.tiefe = 45
print(meineneuekiste.breite)
print(meinekiste.breite)
//Ergebnis
5
25
5
Wie kann das sein? Beim letzten Aufruf von
meinekiste.breite muesste doch, wenn Attribute ohne Initialisierung manipuliert werden koennen, so wie
EyDu es anhand von den Autobeispielen gesagt hat,
25 und nicht
5 heraus kommen.
Es kommt aber immer noch fuer die Instanz
meinekiste.breite 5 heraus. Das heisst, dass
InstanzB konnte die Attribute von
InstanzA nicht manipulieren.
An dieser Stelle frage ich mir wieder, wofuer Initialisieren, wenn eine Instanz die Attribute, die in der Klasse definiert sind, nicht veraendern kann. :K
Entweder habe ich einen Denkfehler oder mir fehlt bei dem ganzen Thema noch eine entscheidende Information oder aber, ich bin viel schlauer als alle anderen hier. aehhhmmm... nope..
Koennte mir das bitte mal einer erklaeren. Ich verzweifle sonst an dem Thema.
Vielen Dank schon mal im Voraus.
Viele Gruesse,
tholle
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Mittwoch 7. Februar 2018, 22:40
von Sirius3
@tholle: Sinn von Instanzen ist, dass sie unabhängig von anderen Instanzen sind. Von daher sollte es Dich nicht verwundern, dass wenn Du Attribute von »meineneuekiste« änderst, Attribute von »meinekiste« gleich bleiben.
Dein Problem ist, dass Du Klassenattribute hast und diese mit Instanzattributen gleichen Namens überschreibst. Klassenattribute sind selten sinnvoll (und dann meist nur als Konstanten) und am Anfang sollte man sie gar nicht benutzen.
Und jetzt kommt »__init__« ins Spiel. Eine Klasse sollte nach der Initialisierung einsatzbereit sein; Deine Instanzen sind erst einsatzbereit, wenn Du auch noch die drei Attribute gesetzt hast. Das korrekte Beispiel ohne Klassenattribute und mit __init__ sähe so aus:
Code: Alles auswählen
class Kiste:
def __init__(self, breite, hoehe, tiefe):
self.breite = breite
self.hoehe = hoehe
self.tiefe = tiefe
def get_volumen(self):
return self.breite * self.hoehe * self.tiefe
// InstanzA
meinekiste = Kiste(5, 10, 15)
print(meinekiste.breite)
//InstanzB
meineneuekiste = Kiste(25, 35, 45)
print(meineneuekiste.breite)
print(meinekiste.breite)
PS: Methoden werden wie Variablen klein_mit_unterstrich geschrieben.
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Mittwoch 7. Februar 2018, 22:48
von pillmuncher
Du bringst die Terminologie völlig durcheinander.
Klassen haben Instanzen, auch Exemplare genannt. Der Text der Klasse definiert diese. Die Klasse ist gewissermaßen ein Bauplan für ihre Instanzen.
Um eine Instanz zu erhalten, muss der Konstruktor der Klasse aufgerufen werden. Diesen schreibt man entweder selbst (mittels __init__ bzw. selten auch mal mit __new__), oder man verwendet den bereits bestehenden der Basisklasse, die meistens object ist. object ist der Name einer Klasse. Ein Objekt ist alles, was Instanz einer Klasse ist, die object als Basisklasse hat.
Objekte haben keine Instanzen, sondern sind Instanzen. Genauso wie jemand der Speisen zubereitet ein Koch ist, aber nicht "einen Koch hat". Oder, angenommen ich habe einen Neffen Stefan, dann bin ich Stefans Onkel, aber ich habe nicht Stefans Onkel.
Jetzt wird es etwas interessanter. In Python3 sind alle Objekte Instanzen von object, selbst Klassen, Funktionen, Methoden und Module. Klassen können also auch Attribute haben. Wenn du eine Klassendefinition hast wie diese:
Dann sind breite. hoehe und tiefe Attribute der Klasse, nicht ihrer Instanzen. Dass man trotzdem auf sie zugreifen kann, als wären sie Instanzattribute, hängt mit Pythons Zugriffsmodell zusammen, macht sie aber nicht zu Instanzattributen. Wenn du eine Instanz hast, sagen wir k1, dann kannst du schreiben:
Nun sind diese Attribute welche der Instanz. Sie "verdecken" die gleichnamigen Attribute der Klasse, überschreiben diese aber nicht. Schau dir das hier mal an:
Code: Alles auswählen
>>> class Kiste:
... breite = 0
... hoehe = 0
... tiefe = 0
...
>>> k1 = Kiste()
>>> k1.breite = 123
>>> k1.hoehe = 456
>>> k1.tiefe = 789
>>> k1.breite, k1.hoehe, k1.tiefe
(123, 456, 789)
>>> Kiste.breite, Kiste.hoehe, Kiste.tiefe
(0, 0, 0)
>>> del k1.breite
>>> del k1.hoehe
>>> del k1.tiefe
>>> k1.breite, k1.hoehe, k1.tiefe
(0, 0, 0)
>>> del Kiste.breite
>>> del Kiste.hoehe
>>> del Kiste.tiefe
>>> k1.breite, k1.hoehe, k1.tiefe
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Kiste' object has no attribute 'breite'
>>> Kiste.breite, Kiste.hoehe, Kiste.tiefe
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Kiste' has no attribute 'breite'
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Donnerstag 8. Februar 2018, 07:46
von tholle
@Sirius3 @Pillmuncher,
vielen Dank euch beiden, dass ihr so schnell und so spaet noch geantwortet habt.
Nach dem 3. Mal Durchlesen eurer Antworten habe ich es, denke ich, verstanden.
Mein entscheidender Denkfehler war, anzunehmen, dass Klassenattribute das Selbe wie Instanzattribute sind. Dass das nicht so ist, wird in euren Beispielen sehr gut erklaert.
Jetzt macht eine Initialisierung beim Objekterstellen (Instanzierung, richtig?) auch Sinn, damit sichergestellt wird, dass fuer jede erstellte Instanz "
unabhaengige" Attribute der Klasse fuer jede erstellte Instanz zur Verfuegung stehen.
Falls ich doch wieder schief liege, reist mein Kartenhaus ruhig wieder ein.
Vielen Dank und Gruss,
tholle
Re: Verständissfrage zu OOP (Anfänger)
Verfasst: Donnerstag 8. Februar 2018, 10:23
von kbr
tholle hat geschrieben:Falls ich doch wieder schief liege, reist mein Kartenhaus ruhig wieder ein.
Das hast Du schon richtig verstanden. Eine der Designstärken von OOP liegt darin, dass Instanzen unterschiedliche Attributwerte haben können. Dies vereinfacht die Modellierung "realer" Objekte.