Auf Liste (Datenstruktur) angewendeter Multiplikationsoperator
-
13-09-2019 - |
Frage
ich lese Wie man wie ein Informatiker denkt Dies ist ein Einführungstext für „Python-Programmierung“.
Ich möchte das Verhalten des Multiplikationsoperators (*
), wenn es auf Listen angewendet wird.
Betrachten Sie die Funktion make_matrix
def make_matrix(rows, columns):
"""
>>> make_matrix(4, 2)
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> m = make_matrix(4, 2)
>>> m[1][1] = 7
>>> m
[[0, 0], [0, 7], [0, 0], [0, 0]]
"""
return [[0] * columns] * rows
Die tatsächliche Ausgabe ist
[[0, 7], [0, 7], [0, 7], [0, 7]]
Die richtige Version von make_matrix Ist :
def make_matrix(rows, columns):
"""
>>> make_matrix(3, 5)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> make_matrix(4, 2)
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> m = make_matrix(4, 2)
>>> m[1][1] = 7
>>> m
[[0, 0], [0, 7], [0, 0], [0, 0]]
"""
matrix = []
for row in range(rows):
matrix += [[0] * columns]
return matrix
Der Grund, warum die erste Version von make_matrix fails (wie im Buch unter 9.8 erklärt) ist das
...jede Zeile ist ein Alias der anderen Zeilen...
ich wundere mich warum
[[0] * columns] * rows
Ursachen ...jede Zeile ist ein Alias der anderen Zeilen...
aber nicht
[[0] * columns]
d.h.warum jeder [0]
in einer Zeile ist kein Alias eines anderen Zeilenelements.
Lösung
ALLES in Python sind Objekte, und Python erstellt niemals Kopien, es sei denn, Sie werden ausdrücklich dazu aufgefordert.
Wenn Sie das tun
innerList = [0] * 10
Sie erstellen eine Liste mit 10 Elementen, alle beziehen sich auf dasselbe int
Objekt 0
.
Da es sich um ganzzahlige Objekte handelt unveränderlich, wenn Sie das tun
innerList[1] = 15
Sie ändern das zweite Element der Liste, sodass es auf eine andere ganze Zahl verweist 15
.Das funktioniert immer, weil int
Objekte Unveränderlichkeit.
Deshalb
outerList = innerList * 5
Werde ein erstellen list
Objekt mit 5 Elementen, jedes davon ist eine Referenz auf das gleiche innerList
genau wie oben.Aber seit list
Objekte sind veränderlich:
outerList[2].append('something')
Ist das gleiche wie:
innerList.append('something')
Weil es sich um zwei Verweise auf die handelt Dasselbe list
Objekt.Das Element landet also in dieser Single list
.Es scheint ein Duplikat zu sein, aber Tatsache ist, dass es nur eines gibt list
Objekt und viele Verweise darauf.
Im Gegensatz dazu, wenn Sie es tun
outerList[1] = outerList[1] + ['something']
Hier sind Sie ja Erstellen ein anderer list
Objekt (mit +
mit Listen ist eine explizite Kopie) und Zuweisen einer Referenz darauf an der zweiten Position von outerList
.Wenn Sie das Element auf diese Weise „anhängen“ (nicht wirklich anhängen, sondern eine andere Liste erstellen), innerList
bleibt davon unberührt.
Andere Tipps
Listen sind keine Grundelemente, sie werden als Referenz übergeben.Eine Kopie einer Liste ist ein Zeiger auf eine Liste (im C-Jargon).Alles, was Sie mit der Liste tun, betrifft alle Kopien der Liste und die Kopien ihres Inhalts, es sei denn, Sie erstellen eine flache Kopie.
[[0] * columns] * rows
Hoppla, wir haben gerade eine große Liste mit Verweisen auf [0] erstellt.Wenn Sie einen ändern, ändern Sie alle.
Ganzzahlen werden nicht als Referenz übergeben, sie werden wirklich kopiert, daher erzeugt [0] * content wirklich viele NEUE Nullen und hängt sie an die Liste an.