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

OOP: Methode der falschen Klasse wird aufgeruden

Beitragvon Twilo » Dienstag 10. Juni 2008, 13:25

Hallo,

ich habe folgendes Klassenkonstrukt

[code=]Klasse1 Klasse1
^ ^
| |
Klasse2 Klasse2
^ ^
| |
Klasse3 Klasse4
^
|
Klasse5[/code]
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
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Beitragvon birkenfeld » Dienstag 10. Juni 2008, 14:10

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:

Beitragvon Twilo » Mittwoch 11. Juni 2008, 09:09

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
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Beitragvon Darii » Mittwoch 11. Juni 2008, 09:14

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: 4866
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Beitragvon EyDu » Mittwoch 11. Juni 2008, 09:57

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:

Beitragvon Twilo » Mittwoch 11. Juni 2008, 10:52

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
EyDu
User
Beiträge: 4866
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Beitragvon EyDu » Mittwoch 11. Juni 2008, 11:20

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:

Beitragvon Twilo » Mittwoch 11. Juni 2008, 11:24

Hallo,

ok

Grüße von und nach Berlin 8)

mfg
Twilo

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder