OOP: Methode der falschen Klasse wird aufgeruden

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
Twilo
User
Beiträge: 109
Registriert: Mittwoch 10. Januar 2007, 19:17
Wohnort: Berlin
Kontaktdaten:

Hallo,

ich habe folgendes Klassenkonstrukt

Code: Alles auswählen

Klasse1    Klasse1
   ^          ^
   |          |
Klasse2    Klasse2
   ^          ^
   |          |
Klasse3    Klasse4
              ^
              |
           Klasse5
die Klasse1 hat eine Methode getRecords

im Konstruktor von der Klasse3 erstelle ich von Klasse5 ein Objekt
self.xyz = Klasse5()

warum gibt mir self.xyz.getRecords() die Records aus, die von der Klasse3 gesetzt werden und nicht die, die von der Klasse4 bzw. Klasse5 gesetzt werden?

mfg
Twilo
[url=http://www.farb-tabelle.de/][b]Farbtabelle[/b][/url]
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Ohne eine Kristallkugel, oder ein bisschen mehr Code der Klassen ist das schwer zu sagen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Twilo
User
Beiträge: 109
Registriert: Mittwoch 10. Januar 2007, 19:17
Wohnort: Berlin
Kontaktdaten:

Hallo,

es wird keine falsche Methode aufgerufen.

in der Klasse1 gibt es eine Methode setRecords.
Bei dieser Methode kommen die richtigen Datensätze an.

sobald das 2. Objekt diese Methode aufruft und Datensätze übergibt, werden dadurch die Datensätze des ersten Objekts überschrieben.

das Beispiel (ist jetzt nicht das sauberste ;)) zeigt es

Code: Alles auswählen

#!/usr/bin/env python

# Rückgabewert:
#{'new': {1: 2, 2: 3}, 'old': {1: 2, 2: 3}}
#{'new': {1: 2, 2: 3}, 'old': {1: 2, 2: 3}}

class Klasse0(object):
    def __init__(self):
        pass


class Klasse1(Klasse0):
    TEST1 = 'old'
    TEST2 = 'new'
    __records = {}
    abc = None

    def __init__(self, abc):
        self.abc = abc
        Klasse0.__init__(self)

    def getRecords(self):
        return self.__records

    def setRecords(self, mode, records):
        self.__records[mode] = records


class Klasse2(Klasse1):
    pass


class Klasse3(Klasse2):
    xyz = None
    def __init__(self):
        self.xyz = Klasse5()
        Klasse1.__init__(self, 1)

    def _getRecords(self):
        return {1: 2, 2: 3}

    def test(self):
        return self.xyz.getRecords()

    def setRecords(self, mode):
        self.xyz.setRecords(mode)
        Klasse1.setRecords(self, mode, self._getRecords()) # <--- warum überschreibt diese Zeile die Records von der vorherigen zeile?


class Klasse4(Klasse2):
    def _getRecords(self):
        return {2: 3, 3: 4}


class Klasse5(Klasse4):
    def __init__(self):
        Klasse0.__init__(self)
        Klasse1.__init__(self, 2)

    def setRecords(self, mode):
        Klasse1.setRecords(self, mode, self._getRecords())


if __name__ == '__main__':
    klasse3 = Klasse3()
    klasse3.setRecords(klasse3.TEST1)
    klasse3.setRecords(klasse3.TEST2)

    print klasse3.getRecords()
    print klasse3.test()

Code: Alles auswählen

#!/usr/bin/env python

# Rückgabewert:
#{1: 2, 2: 3}
#{2: 3, 3: 4}

class Klasse0(object):
    def __init__(self):
        pass


class Klasse1(Klasse0):
    __records = {}
    abc = None

    def __init__(self, abc):
        self.abc = abc
        Klasse0.__init__(self)

    def getRecords(self):
        return self.__records

    def setRecords(self, records):
        self.__records = records


class Klasse2(Klasse1):
    pass


class Klasse3(Klasse2):
    xyz = None
    def __init__(self):
        self.xyz = Klasse5()
        Klasse1.__init__(self, 1)

    def _getRecords(self):
        return {1: 2, 2: 3}

    def test(self):
        return self.xyz.getRecords()

    def setRecords(self):
        self.xyz.setRecords()
        Klasse1.setRecords(self, self._getRecords())


class Klasse4(Klasse2):
    def _getRecords(self):
        return {2: 3, 3: 4}


class Klasse5(Klasse4):
    def __init__(self):
        Klasse0.__init__(self)
        Klasse1.__init__(self, 2)

    def setRecords(self):
        Klasse1.setRecords(self, self._getRecords())


if __name__ == '__main__':
    klasse3 = Klasse3()
    klasse3.setRecords()

    print klasse3.getRecords()
    print klasse3.test()
warum wird beim erasten Beispiel nicht folgendes zurückgegeben?
{'new': {1: 2, 2: 3}, 'old': {1: 2, 2: 3}}
{'new': {2: 3, 3: 4}, 'old': {2: 3, 3: 4}}
liegt es evtl. daran, dass __records im ersten Beispiel ein Dictionary ist?

mfg
Twilo
[url=http://www.farb-tabelle.de/][b]Farbtabelle[/b][/url]
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Ja, weil all deine Objekte auf ein und dasselbe dictionary zugreifen. Initialisiere es im __init__ der Klasse1 und du bist deine Probleme los.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Vielleicht um den Unterschied noch einmal ganz deutlich zu machen:

Code: Alles auswählen

class MyClass(object):
    eggs = 1    #(1)

    def m1(self):
        self.spam = 2    #(2)

    def m2(self):
        self.eggs = 3    #(3)
Bei (1) Bindest du "eggs" and die Klasse "MyClass", du kannst also von außen auf sie mit MyClass.eggs zugreifen, oder aber über eine Instanz von MyClass. Dass liegt an Suchstrategie beim Suchen von Namen in Objekten.

Bei (2) Bindest du "spam" an eine Instanz der Klasse MyClass. Daher das self. Auf das "spam" kannst du nur über die Instanz zugreifen:

Code: Alles auswählen

x = MyClass()
print x.spam
Bei (3) Erzeugst du einen "eggs" welches an eine Instanz gebunden wird. Dieses verdeckt lediglich das "eggs" aus (1). Mit "MyClass.eggs" kannst du immer noch auf das alte zugreifen.

Wenn du also eine Variable für jedes Objekt benötigt, dann initialisieren sie einfach, wie Darii schon geschrieben hat, immer in einer der __init__-Methoden.
Twilo
User
Beiträge: 109
Registriert: Mittwoch 10. Januar 2007, 19:17
Wohnort: Berlin
Kontaktdaten:

Hallo,

danke!
da wär ich, glaube ich, von alleine nicht drauf gekommen :?

Code: Alles auswählen

class Klasse1(Klasse0):
    TEST1 = 'old'
    TEST2 = 'new'
    abc = None
    __records = None

    def __init__(self, abc):
        self.abc = abc
        self.records = {}
        Klasse0.__init__(self)
ist dagegen etwas einzuwenden, oder sollte ich "__records = None" komplett weglassen?

mfg
Twilo
[url=http://www.farb-tabelle.de/][b]Farbtabelle[/b][/url]
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ja, lass es weg. Das selbe gilt für abc. Offensichtlich sollen beide zur Instanz gehören.
Twilo
User
Beiträge: 109
Registriert: Mittwoch 10. Januar 2007, 19:17
Wohnort: Berlin
Kontaktdaten:

Hallo,

ok

Grüße von und nach Berlin 8)

mfg
Twilo
[url=http://www.farb-tabelle.de/][b]Farbtabelle[/b][/url]
Antworten