Code: Alles auswählen
class Node(object):
def __init__(self, data, next_node=None):
self.data = data
self.next_node = next_node
class LinkedList(object):
def __init__(self):
self.items = None
def __iter__(self):
node = self.items
while node:
yield node.data
node = node.next_node
def __len__(self):
return sum(1 for _ in self)
def prepend(self, item):
self.items = Node(item, self.items)
def main():
linked_list = LinkedList()
linked_list.prepend(23)
linked_list.prepend(42)
linked_list.prepend(4711)
print(len(linked_list))
for item in linked_list:
print(item)
if __name__ == '__main__':
main()
Ich denke was Sirius3 meinte war der Code den Du da geschrieben hast. Denn so etwas habe ich in Python noch nicht gesehen und sehe auch nicht wirklich wo man das braucht. Wenn ich mal *vermuten* dürfte was Du da tust, dann sieht das eher nach einer eigenen Koordinaten-Klasse und einer Polygon-Klasse aus und nach Code um zwischen der besch…eidenen API von Tk hin und her zu wandeln.
Zu Deinen beiden Codebeispielen: Namen sind in Python nicht gleichzusetzen mit Adressen oder Schachteln wo man Dinge/Werte hinein tut sondern Haftnotizen die man an Objekte klebt. Das ist eine Zuweisung. Nicht etwas in eine Schachtel mit dem Namen `x` stecken, sondern eine Haftnotiz wo `x` drauf steht an ein Objekt kleben. Die Adressen gehören in Python fest zu den Werten.
Dein erstes Codebeispiel:
a=[2]: Es wird eine Liste mit dem Element 2 erstellt und da wird ein Zettel mit `a` draufgeklebt.
b=a: Dann wird ein Zettel mit `b` auf das Objekt geklebt wo der Zettel mit `a` dran klebt. An der Liste kleben nun zwei Haftnotizen.
a=[3]: Es wird eine Liste mit dem Element 3 erstellt und da wird der Zettel mit `a` dran geklebt, wofür er von der anderen Liste entfernt werden muss, weil es (in einem Namensraum) immer nur einen Zettel mit dem gleichen Namen gibt, und der immer nur maximal an einem Objekt kleben kann.
print(b): Es wird das Objekt an dem der Zettel `b` klebt ausgegeben, also die Liste mit der 2 darin. Denn das umkleben der Zettels mit `a` hat keinen Einfluss auf irgend etwas anderes. Keines der beiden Objekte, weder das wo der Zettel vorher klebte, noch das wo er dann drauf geklebt wird, hat irgend einen Einfluss auf die beteiligten Objekte.
Zweites Codebeispiel:
a=[2]: Wie im ersten Beispiel.
b=a: Ebenfalls wie im ersten Beispiel.
a[0]=3: Hier wird das Objekt mit den Zettel `a` genommen und dessen erstes Element referenziert nun das Objekt 3. Und nicht mehr das Objekt 2, weil an einem Index immer nur *ein* Objekt referenziert werden kann.
print(b): Wie im ersten Beispiel wird das Objekt ausgegeben auf dem Zettel `b` klebt. Das ist die Liste auf der beide Zettel kleben, weil Zettel `a` ja nicht zu einem anderen Objekt bewegt wurde, also die Liste in der wegen der Zeile hiervor das Element 3 steckt.
Das ist ein ”Riesenunterschied” weil die vorletzte Zeile in den beiden Beispielen etwas unterschiedliches macht. Es wird nicht der Name neu gebunden, an ein *anderes* Listenobjekt, sondern es wird die eine Liste an die beide Namen gebunden sind *verändert*. Und riesig ist der Unterschied IMHO auch nur weil Du im Denkmuster von C (oder einer ähnlichen Sprache) fest hängst, wie man an den Semikolons erahnen kann.
Wobei ich auch sagen würde das Java im grossen und ganzen auch wie Python funktioniert. Bei den Wertdatentypen unter den Grunddatentypen macht es keinen Unterschied das Java die anders behandelt, weil die unveränderlich sind, also vom Effekt her kein Unterschied besteht. Wenn man diese Art des Objektmodells nicht versteht, dann kann man weder Java noch Python sinnvoll programmieren.
Und JavaScript funktioniert an der Stelle auch so wie Python, Ruby, Perl, Java, …. Das ist also wirklich nichts ”exotisches” was ausgerechnet Python anders machen würde als alle anderen Programmiersprachen.
Da pillmuncher Lisp ins Spiel brachte: Auch dort gibt es keinen Pointer-Datentyp aber verkettete Listen sind *der* Grunddatentyp und sie werd aus Cons-Zellen erstellt, also im Grunde so etwas wie Tupel die aus einem Wert und einer nächsten Cons-Zelle oder einem ”Endkennzeichen” bestehen, letztlich also so etwas wie die `Node`-Klasse im Python-Beispiel weiter oben.
Mal als Beispiel in Hy (in Python implementierter Lisp-Dialekt):
[codebox=clojure file=Unbenannt.txt]#!/usr/bin/env hy
(require [hy.contrib.loop [loop]])
(defn length [a-list]
(if (empty? a-list) 0 (inc (length (cdr a-list)))))
(defmain [&rest args]
(setv a-list '())
(setv a-list (cons 23 a-list))
(setv a-list (cons 42 a-list))
(setv a-list (cons 4711 a-list))
(print (length a-list))
(loop [[items a-list]]
(unless (empty? items)
(print (car items))
(recur (cdr items)))))[/code]
Also so könnte `length` in Lisp aussehen wenn man es selber implementieren müsste, natürlich gibt es das schon und da solche Listen *die* Grunddatenstruktur in Lisp sind in der sogar die Programme repräsentiert werden, gibt es auch eine syntaktische Möglichkeit solche Listen zu schreiben: Mit Klammern, wie das Programm selbst auch. Das hier wäre dann etwas näher an dem was man in Lisp schreiben würde:
[codebox=clojure file=Unbenannt.txt]#!/usr/bin/env hy
(require [hy.contrib.loop [loop]])
(defmain [&rest args]
(let [a-list '(4711 42 23)]
(print (len a-list))
(loop [[items a-list]]
(unless (empty? items)
(print (car items))
(recur (cdr items))))))[/code]
Und da Hy auf Python abgebildet wird, gibt es die `for`-Form, die das `loop`-Makro ersetzen kann und man bei folgendem landet:
[codebox=clojure file=Unbenannt.txt]#!/usr/bin/env hy
(defmain [&rest args]
(let [a-list '(4711 42 23)]
(print (len a-list))
(for [item a-list] (print item))))[/code]