Klassen und erben

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
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Hi!

Ich habe irgendwie besonders Mühe mit Klassen =/. Ich hab also zum x-ten mal das Tutorial darüber gelesen, und verstehe nun schon etwas besser, wann self. kommt usw.
Ich komm aber irgendwie nicht weiter mit dem "erben" (mal naiv direkt übersetzt ^^).... Die Idee dahinter verstehe ich zwar, aber praktisch klappts irgendwie nicht ganz =).

Hier ein kleines Script, wo ich Klassen und deren Funktionen auf verschiedene Arten definiere / aufrufe (mir ist bewusst, dass man eine Funktion nie ausserhalb der eigenen Klasse definieren sollte, aber es ging mir nur ums Verständnis, wie es gehen würde):

Code: Alles auswählen

def second(self):
	print self.y

class Bass_Class:
	def __init__(self, x, y):
		self.x = x
		self.y = y
	def first(self):
		print self.x
	second = second

class First_Derived_Class(Bass_Class):
	def __init__(self, z):
		self.z = z
	def third(self):
		print self.z
	def fourth(self):
		Bass_Class.__init__(self, "Hi, fourth #1", "Hi, fourth #2")
		print self.x
		print self.y

class Second_Derived_Class(Bass_Class):
        def __init__(self, x, y, v):
            Bass_Class.__init__(self, x, y)
            self.v = v
            self.args = (x, y, v)
        def fifth(self):
            for i in self.args:
                print i

b = Bass_Class("Hi, this is the first message", "This is the second")
d = First_Derived_Class("And this is the third")
s = Second_Derived_Class("Hi, this is the first message again", "This is the second again", "This is the fifth")

b.first()
b.second()
d.third()
d.fourth()
s.first()
s.fifth()
Nun meine Schwierigkeiten:

1. Wenn ich die Bass_Class.__init__() in der First_Derived_Class aufrufe (Zeile 18), muss ich x und y wieder "definieren". Wie kann ich machen, dass eben das x und y nur einmal definieren muss, und diese Zuordnung dann eben geerbt wird? =/

[EDIT... hab mir Frage 2 gerade selbst beantwortet^^]

Danke für ein bisschen Hilfe & Kritik =).

lg Seeker

PS: entschuldigt die leicht chaotischen Variabelnamen... :/
Zuletzt geändert von Seeker am Dienstag 20. Oktober 2009, 17:43, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn du die `__init__()`-Methode der Klasse, von der du erbst, überschreibst, dann musst du auch wieder alle Namen übernehmen. Das macht Python nicht von alleine. Oft erbt man ja, weil man nur eine einzelne Methode überschreiben möchte. Man sollte es mit der Vererbung IMHO sowieso nicht übertreiben. Häufig ist es besser, die zusätzliche Klasse als Attribut zu verwenden.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

snafu hat geschrieben: Häufig ist es besser, die zusätzliche Klasse als Attribut zu verwenden.
Du hast schon recht, doch hier möchte ich die Aussage modifzieren, denn das ist die Frage nach Haben und Sein: Hat die Klasse ein Objekt (bzw. eine Instanz einer anderen Klasse) als Attribut oder ist die betreffene Klasse etwas Ähnliches wie eine "Oberklasse"? Im ersten Fall vererbt man nicht, im zweiten mitunter schon. Es kommt also drauf an - wie fast immer ;-).
Aber ich bin mir sicher, das hast Du gemeint.
crs
User
Beiträge: 42
Registriert: Dienstag 14. Juli 2009, 13:24

bin mir jetzt nicht ganz sicher ob ich die frage richtig verstanden habe, aber evtl. suchst du *arguments bzw. **keywords?

Code: Alles auswählen

class Foo(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Bar(Foo):
    def __init__(self, z, *args, **kwargs):
        Foo.__init__(self, *args, **kwargs)
        self.z = z
ob vererbung dann in einem speziellen fall auch wirklich sinnvoll ist oder nicht ist natuerlich nochmal eine andere frage, so allgemein kann man dazu aber eigentlich keine wirkliche aussage machen.

und p.s.: BaseClass, nicht Bass_Class ;)
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Danke für die Antworten =).
Alles klar... zu viele Klassen und Unterklassen sind also oft vermeidbar :). Aber viele Python Programme, die ich gesehen habe, arbeiten trotzdem mit Klassen (und z.T. Unterklassen), und ich wollte einfahc die Syntax verstehen =).

@crs:

Also, das *args und **kwargs geben mir einfach die Möglichkeit, eine unbestimmte Anzahl Argumente einzufügen, oder?

Ich verstehe vor allem nicht, wie ich in der Oberklasse definierte Variabeln in der Unterklasse nutzen kann.
Bsp.
Oberklasse macht irgendwas mit x und y. Etwas später kommt dann die Unterklasse mit einer dritten Variabel z, wobei ich aber x und y auch wieder brauche.
Eine Anwendung könnte z.B. sein, dass man immer x und y hat, aber je nach dem, was für ein Objekt man verarbeitet (also z.B: Dateityp), muss man etwas anderes machen.
Dann könnte man eine Oberklasse mit x und y kreieren, und dann eine Reihe von Unterklassen, die dann mit x, y und einer neuen Variable z etwas anstellen.

Code: Alles auswählen

class Foo:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Bar(Foo):
    def __init__(self, z):
        Foo.__init__(self, x, y) ##Werte werden aus Foo genommen, ich muss sie nicht neu definieren
        self.z = z
    def add(self):
        print (self.x + self.y +self.z)
        ##(wobei x und y aus Foo() sind, ich möchte die gleichen Werte weiterverwenden)

##Aufrufen müsste dann irgendwie so aussehen:
f = Foo(10, 20)
b = Bar(30) ##--> die werte von x und y werden durch das Foo.__init__(self, x, y) also gleich übernommen.
b.add()

##Ausgabe:
60
Ist das überhaupt möglich ?
Zuletzt geändert von Seeker am Dienstag 20. Oktober 2009, 13:13, insgesamt 1-mal geändert.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Ähm nein nicht direkt...

Du musst natürlich die Werte in der Klasse setzen
Bar.__init_ muss so aussehen

Code: Alles auswählen

__init__(x,y,z):
  Foo.__init__(x,y)
..
Bar(1,2,3)
Ich glaube du hast das Vererbungsprinzip nicht richtig verstanden.

Vermutlich willst du so was:

Code: Alles auswählen

class Foo(object):
  def __init__(self, x, y):
    self.x = x
    self.y = y
class Bar(object):
  def __init__(self, z, foo)
    self.z = z
    self.foo = foo
    print foo.x, foo.y, z

foo = Foo(1,2)
bar = Bar(3, foo)
  
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

hm... also muss ich zwingend wieder x und y neu angeben?
Ich kann einfach die "Verarbeitung" von x und y übernehmen, aber die Werte können nicht "vererbt" werden?

:idea: In meinem Fall mit den Dateitypen würde man die Oberklasse also gar nie aufrufen... sondern direkt die Unterklasse aufrufen, wobei x und y einfach durch die Oberklasse verarbeitet werden?
Dann wär ja einiges klarer :D ... danke :)!
Ich hatte das mit dem "erben" wohl falsch verstanden.

lg Seeker

EDIT: War ich wohl zu langsam. Genau das hatte ich (falsch) gemeint. :roll:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie sollte denn so was gehen, wie Du es Dir vorstellst?

Ich greife mal Dein Beispiel auf:

Code: Alles auswählen

f = Foo(10, 20)
b = Bar(30) 
# b.x=10, b.y=20, b.z=30
another_f = Foo(100, 200)
another_bar = Bar(300)
# welche Werte bekommt denn nun another_bar?
# Die von f oder another_f?
Selbst wenn man obiges irgend wie per Konvention lösen könnte, so bliebe ja die Einschränkung, dass man um ein Objekt einer tiefsten Klasse anlegen zu können, erst einmal für jede Eltern-Klasse ein neues Objekt anlegen müßte... das wäre nicht grad toll, oder? ;-)
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Ja, ich sehe das Problem =), ich verstehe ja jetzt au den Sinn des ganzen besser ;).

Aber mal nur als Argument:
Man könnte Unterklassen z.B. irgendwie so machen:

Code: Alles auswählen

f = Foo(10, 20)
b = Bar(*x, *y, 30)
Dann würde per default das x und y von der Oberklasse genommen, aber man könnte trotzdem neuen Werte eingeben.

Aber ich schätze, dass man dies irgendwie mit

Code: Alles auswählen

def Bar:
    def __init__(self, z, x = Foo.x, y = Foo.y):
        self.x = x
        self.y = y
        self.z = z
machen
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Seeker hat geschrieben:Ja, ich sehe das Problem =), ich verstehe ja jetzt au den Sinn des ganzen besser ;).

Aber mal nur als Argument:
Man könnte Unterklassen z.B. irgendwie so machen:

Code: Alles auswählen

f = Foo(10, 20)
b = Bar(*x, *y, 30)
Dann würde per default das x und y von der Oberklasse genommen, aber man könnte trotzdem neuen Werte eingeben.
Du verwechselst da noch Klassen und Objekte von Klassen!

Was passiert denn bei?

Code: Alles auswählen

f = Foo(10, 20)
another_foo = Foo(30, 50)
b = Bar(*x, *y, 30)
Der Interpreter müßte ja erst einmal ein Mapping herstellen zwischen Objekten der Oberklasse und denen der Unterklasse. Wenn er das tatsächlich schaffen sollte, so muss er ja noch entscheiden, welche Werte denn jetzt übernommen werden! Und was passiert, wenn ein Objekt gelöscht wird? Verbleiben dann die Werte?

ice2k3 hatte Dir doch quasi eine Lösung dafür angegeben, wie man so etwas durchaus elegant lösen kann, wenn man es mal braucht.
crs
User
Beiträge: 42
Registriert: Dienstag 14. Juli 2009, 13:24

Seeker hat geschrieben:hm... also muss ich zwingend wieder x und y neu angeben?
Ich kann einfach die "Verarbeitung" von x und y übernehmen, aber die Werte können nicht "vererbt" werden?
die werte von x und y gehören zu einer bestimmten Instanz der Klasse und werden daher nicht mit vererbt. vererbt werden nur die attribute selbst.

mit dem code von vorhin wuerde daher nur so etwas gehen:

Code: Alles auswählen

In [1]: f = Foo(23, 42)

In [2]: f.x
Out[2]: 23

In [3]: b = Bar(1337, 23, 42)

In [4]: b.x
Out[4]: 23

In [5]: b.z
Out[5]: 1337
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du hast das Prinzip von Klassen wohl noch nicht richtig verstanden. Du kannst beliebig viele Exemplare einer Klasse erstellen. Diese Exemplare haben alle (prinzipiell) keine Ahnung, was in den anderen Exemplaren geschieht.

Mit einer Klasse Fahrzeug kannst du tausende Exemplare eines Fahrzeugs erstellen, kein Fahrzeug weiß aber etwas von den anderen Fahrzeugen. Zum Beispiel, wo diese gerade stehen oder welches Nummernschild sie haben. Ein Exemplar weiß nur wo es selbst steht und welches Nummernschild es selbst hat.

Vererbung kannst du dir dann so vorstellen, dass eine Klasse Auto von Fahrzeug erbt, oder LKW von Fahrzeug erbt. Autos und LKWs sind Fahrzeuge und können deren Eigenschaften Annehmen. Alle Exemplare von Fahrzeug, Auto und LKW kennen aber immer noch nur ihre eigenen Eigenschaften.

Code: Alles auswählen

class Fahrzeug(object):
    def __init__(self, nr):
        self.nr = nr

class Auto(Fahrzeug):
    def __init__(self, nr, sitze):
        Fahrzeug.__init__(self, nr)
        self.sitze = sitze

class LKW(Fahrzeug):
    def __init__(self, nr, laderaum):
        Fahrzeug.__init__(self, nr)
        self.laderaum = laderaum

f1 = Fahrzeug("F1")
f2 = Fahrzeug("F2")
a1 = Auto("A1", 5)
a2 = Auto("A2", 2)
l1 = LKW("L1", 23)
l2 = LKW("L2", 42)

print f1.nr
print f2.nr
print a1.nr
print a2.nr
print l1.nr
print l2.nr
print a1.sitze
print a2.sitze
print l1.laderaum
print l2.laderaum
Das Leben ist wie ein Tennisball.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Ja, jetzt verstehe ichs =).
Jetzt verstehe ich vor allem den Sinn der Klassen besser. Ich glaube, ich hatte in meinem Kopf noch ein Wirrwarr mit Variabeln der Klasse und Methoden einer Klasse usw.
Bei weiterem Ausprobieren ist mir nun auch noch klar geworden, weshalb meine Idee in der Praxis nicht so viel Sinn macht =P.

Danke an alle =)

lg Seeker
Antworten