Listen in Klassen

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
Modibo
User
Beiträge: 22
Registriert: Samstag 19. Februar 2011, 16:06

Hallo zusammen,

werden Listen in Klassen irgendwie anders verarbeitet?

Ich will die Einträge einer Matrix, dargestellt durch eine geschachtelte Liste, neu setzen. Dazu habe ich erstmal folgendes Beispiel geschrieben:

Code: Alles auswählen

m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
for i in range(3):
    for j in range(3):
        m[i][j] = float(input("a_"+str(i+1)+str(j+1)+":"))
Das funktioniert schon ganz gut.

Mein jetziger Ansatz als Methode dazu sieht so aus:

Code: Alles auswählen

class Matrix(object):                
    def __init__(self, zeilen, spalten):
        if zeilen>0 and spalten>0:
            self.zeilen = zeilen
            self.spalten = spalten

            self.matrix = []
            self.__zeilenvektor = []
            
            for i in range(self.spalten):
                self.__zeilenvektor.append(0)

            for i in range(self.zeilen):
                self.matrix.append(self.__zeilenvektor)

    def set_matrix(self):
        for i in range(self.spalten):
            for j in range(self.zeilen):
                self.matrix[i][j] = float(input("a_"+str(i+1)+str(j+1)+":"))
Das Problem ist, dass die Matrix, deren Einträge mit der Methode set_matrix() gesetzt werden, nicht stimmt. Die Einträge des letzten Zeilenvektors werden in alle andere Zeilen der Matrix geschrieben.

Wo ist der Unterschied und was muss ich ändern?

Gruß
Modibo
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Dein Problem hat überhaupt nichts mit Klassen zu tun. Guckstu:

Code: Alles auswählen

>>> a = [[] for _ in range(10)]
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0].append(123)
>>> a
[[123], [], [], [], [], [], [], [], [], []]
>>> b = [[]] * 10
>>> b
[[], [], [], [], [], [], [], [], [], []]
>>> b[0].append(123)
>>> b
[[123], [123], [123], [123], [123], [123], [123], [123], [123], [123]]
Das stichwort lautet Objektidentität. Im Falle von a werden zehn leere Listen erstellt und diese werden zu Elementen einer neuen Liste. Im Falle von b wird dieselbe Liste zehnmal als Element zu einer Liste hinzugefügt. Dein Code macht vom Prinzip her genau dasselbe wie im Beispiel mit b.
In specifications, Murphy's Law supersedes Ohm's.
Modibo
User
Beiträge: 22
Registriert: Samstag 19. Februar 2011, 16:06

Ah!
Ich glaub, ich hab's verstanden. :D
Vielen Dank!

---
Ich hab in Zeile 14 jetzt einfach self.matrix.append(self.__zeilenvektor[:]) reingeschrieben und es funktioniert ganz wunderbar.
BlackJack

@Modibo: Das mag funktionieren ist aber komisch. Warum erstellst Du nicht neue Listen statt immer wieder die selbe zu füllen und dann zu kopieren? Und warum ist diese Liste an das Objekt gebunden? Und warum mit zwei führenden Unterstrichen?

`self.zeilen` und `self.spalten` sind irreführend weil die Attribute keine Zeilen oder Spalten enthalten sondern jeweils eine Zahl. Eigentlich sind die Attribute auch redundant weil die Information auch von `self.matrix` abgefragt werden kann da Listen ihre eigene Länge kennen und man die mit `len()` abfragen kann.

Das ``if`` in der `__init__()` ist *so* keine gute Idee, denn wenn die Bedingung nicht erfüllt ist, bekommt man ein unbenutzbares `Matrix`-Objekt.

`set_matrix()` ist auch kein guter Name weil man bei einer `set_methode()` eigentlich erwartet das man dort eine Matrix beziehungsweise die Daten übergeben kann. Andererseits sind triviale Setter in Python ein „code smell”. Und es sieht so aus als würdest Du dort Programmlogik mit Benutzerinteraktion vermischen, was man auch nicht machen sollte.

Die API ist ein wenig ungewöhnlich. Erst ”leere” Strukturen mit Platzhaltern zu erstellen um die dann alle durch die tatsächlichen Werte zu ersetzen ist in Python nicht üblich. Da würde man einfach die Struktur mit den tatsächlichen Werten aufbauen.

Edit: Die ”pythonischere” Variante für das erste Beispiel:

Code: Alles auswählen

    matrix = list()
    for i in range(1, 4):
        row = list()
        for j in range(1, 4):
            row.append(float(input('a_{0}{1}: '.format(i, j))))
        matrix.append(row)
Für die Klasse gibt es kein besseres Beispiel weil da irgendwie der Sinn fehlt das in eine Klasse zu stecken. Das wird erst sinnvoll wenn es Operationen gibt für diesen Datentyp.
Antworten