Matroids Matheplanet Forum Index
Moderiert von matph
Informatik » Programmieren » Python - Identisch vs. gleich
Autor
Kein bestimmter Bereich J Python - Identisch vs. gleich
Red_
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 28.09.2016
Mitteilungen: 984
  Themenstart: 2021-10-19

Hallo, ich lerne gerade Python und habe folgendes festgestellt: \sourceon nameDerSprache x = 3 y = x y = y + 1 print(x) print(y) \sourceoff Mein Output: \sourceon nameDerSprache 3 4 \sourceoff Jetzt: \sourceon nameDerSprache name = ["Mike", "Jacob", "Lua"] name2 = name name2.pop() print(name) print(name2) \sourceoff Mein Output: \sourceon nameDerSprache ['Mike', 'Jacob'] ['Mike', 'Jacob'] \sourceoff Warum werden die Variablen als unterschiedliche Objekte behandelt, aber die Listen als ein identisches Objekt, obwohl ich die gleichen Befehle benutzt habe?


   Profil
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 3037
  Beitrag No.1, eingetragen 2021-10-19

Zahlen sind immutable und werden immer als Kopie übergeben, Listen sind standardmäßig mutable und werden per Referenz übergeben. Letzteres ist in den meisten Programmiersprachen so und keineswegs eine Besonderheit von Python. (Objekte zu kopieren ist recht schwierig, aufwendig und in der Regel unerwünscht) Falls du komplexere Objekte tatsächlich kopieren willst, musst du dich selbst darum kümmern. (Bspw. durch Nutzen eines Copy-Konstruktors, sofern vorhanden) \sourceon Python \numberson >>> A = [1,2,3] >>> B = list(A) >>> A [1, 2, 3] >>> B [1, 2, 3] >>> B.pop() 3 >>> B [1, 2] >>> A [1, 2, 3] \sourceoff


   Profil
Red_
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 28.09.2016
Mitteilungen: 984
  Beitrag No.2, vom Themenstarter, eingetragen 2021-10-19

Ah okay, vielen Dank! PS: Es gibt die Funktion (ich weiß nicht, ob man sowas Funktion nennt) B = A.copy()


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.3, eingetragen 2021-10-19

Vielleicht noch etwas genauer: mit immutable/mutable hat das ganze nichts zu tun. Bei einer Zuweisung wie V = wird der Ausdruck auf der rechten Seite ausgewertet und das Ergebnis dieser Auswertung der Variablen V zugewiesen. Ein Ausdruck wie [1,2,3] hat als Ergebnis aber nicht die Liste, sondern eine Referenz auf die (in dem Fall neu erzeugte, und irgendwo in den Speicher gelegte) Liste. Keine Variable enthält jemals eine Liste oder andere komplizierte Objekte. Nach V = [1,2,3] enthält V also eine Referenz, und nach einem darauffolgenden W = V enthält W dieselbe Referenz, weil das Ergebnis der Auswertung des Ausdrucks V der (vollständige!) Inhalt von V ist, und dies ist eben eine Referenz. Bei immutable Objekten verhält es sich genau gleich. Man kann eben nur über eine Referenz auf ein immutable Objekt dieses nicht verändern, sodass eine Referenzkopie sich semantisch (also auch abgesehen von Performance) genauso verhält wie eine tiefere Kopie.


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.4, eingetragen 2021-10-20

@tactac Der erste Satz ist aber verwirrend bis falsch, denn das hat *alles* mit immutable vs. mutable zu tun, denn genau das ist der einzige Unterschied zwischen den beiden Fällen. Es werden nur Referenzen übergeben, nie Kopien von Werten. @Red_ Wenn man etwas auf einem Objekt aufruft, dass an dieses Objekt gebunden ist, also auf das Objekt zugreifen kann obwohl es nicht explizit übergeben wurde, dann nennt man das eine Methode. Wenn ``A`` eine Liste ist, dann ist ``A.copy()`` äquivalent zu ``list.copy(A)``.


   Profil
Finn0
Junior Letzter Besuch: im letzten Quartal
Dabei seit: 30.06.2021
Mitteilungen: 13
  Beitrag No.5, eingetragen 2021-10-20

In diesen veränderbaren Datenstrukturen stecken die Dämonen drin. Vom Unheil dieser Abwege wurde bereits in Struktur und Interpretation von Computerprogrammen berichtet, ja es bräuchte ein unerbittliches Typsystem zu ihrer Bändigung. Darum ist es besser, diese Abwege nicht einzuschlagen. Eine sündhaftes Programm wie \sourceon Python def s0(a): a.sort() \sourceoff könnt ihr läutern zu: \sourceon Python def s1(t): return tuple(sorted(t)) \sourceoff Die Reinwaschung von Daten erledigt ihr auf die folgende Art: \sourceon Python def purify(t): T = type(t) if T is tuple or T is list: return tuple(purify(x) for x in t) elif T is set or T is frozenset: return frozenset(purify(x) for x in t) elif T is int or T is float or T is complex or T is str: return t else: raise ValueError("unreachable") \sourceoff


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.6, eingetragen 2021-10-20

@Finn0: Wenn man ein unerbittliches Typsystem und nur 4 von 6 Grunddatentypen haben möchte, und beispielsweise auf Wörterbücher (`dict`) ganz verzichten möchte, dann ist man bei einer dynamischen, objektorientierten Programmiersprache wohl eher falsch. ”unreachable” ist wohl eher Wunschdenken, denn es gibt ja ”unendlich” viele Werte die in diesem Zweig landen werden. Sogar ”reine” Werttypen, die eigentlich dieser fundamentalen Religion folgen würden. Die Funktion scheint von fanatischen Extremisten geschrieben worden zu sein. 😱 Der Verdacht erhärtet sich auch durch die Typprüfung mit `type()` statt mit `isinstance()`, die wesentlich mehr Kandidaten reinigen würde. Aber es kommen hier ausser reinrassigen `set` und `list` nur sowieso schon gereinigte durch die Säuberung. Aber wie das oft bei religiösen Eiferern so ist, nehmen sie es dann mit anderen, wesentlichen Teilen nicht so ernst. Die Schreibweise von `T` entspricht ja wohl nicht dem heiligen Buch PEP8! Das geht gar nicht!!1!!elf! 😈


   Profil
Finn0
Junior Letzter Besuch: im letzten Quartal
Dabei seit: 30.06.2021
Mitteilungen: 13
  Beitrag No.7, eingetragen 2021-10-20

Sowohl in PEP 484 als auch in PEP 8, Abschnitt Type variable names kommt T als Typvariable vor. Dort ist sie zwar der statischen Typprüfung angedacht, aber immerhin eine Typvariable.


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.8, eingetragen 2021-10-20

\quoteon(2021-10-20 01:39 - __blackjack__ in Beitrag No. 4) @tactac Der erste Satz ist aber verwirrend bis falsch, denn das hat *alles* mit immutable vs. mutable zu tun, denn genau das ist der einzige Unterschied zwischen den beiden Fällen. Es werden nur Referenzen übergeben, nie Kopien von Werten. \quoteoff Es werden Kopien von Werten übergeben. Diese Werte sind manchmal Referenzen.


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.9, eingetragen 2021-10-20

@tactac: Dann klingt das falsch, denn da wird *immer* das gleiche gemacht, egal ob man eine ganze Zahl oder eine Liste hat, es wird *immer* die Referenz auf das Objekt übergeben/zugewiesen und *nie* ein Wert kopiert den es *in der Sprache* als Typ gäbe. Bei ``a = b`` oder ``frobnicate(b)`` passiert mit `b` immer genau das gleiche — es wird nie der Wert von `b` kopiert, was auch immer `b` für einen Typ hat. Bei: \sourceon Python a += b \sourceoff ist es der Python-Implementierung total egal was `a` und `b` für Typen haben. Ob das nun Zahlen sind oder Listen, beide Werte werden exakt gleich behandelt. Es sind die Typen selber die, bzw. deren Autoren, entscheiden ob sie veränderbar sind (`list`) oder nicht (`int`) indem sie Methoden zur Verfügung stellen die das Objekt verändern können, oder ausschliesslich solche, die das *nicht* tun. `__iadd__()` von `list` verändert die Liste, und `__iadd__()` von `int` liefert ein neues `int`-Objekt als Ergebnis. *Das* ist der beobachtbare Unterschied, der einzig auf immutable vs. immutable zurückzuführen ist. Python selbst kopiert bei Zuweisungen an einfache Namen oder Parameterübergaben nie unaufgefordert Werte. Das muss man als Programmierer immer explizit selbst machen.


   Profil
Finn0
Junior Letzter Besuch: im letzten Quartal
Dabei seit: 30.06.2021
Mitteilungen: 13
  Beitrag No.10, eingetragen 2021-10-20

\quoteon(2021-10-20 14:07 - __blackjack__ in Beitrag No. 9) [...] da wird *immer* das gleiche gemacht, egal ob man eine ganze Zahl oder eine Liste hat, es wird *immer* die Referenz auf das Objekt übergeben/zugewiesen und *nie* ein Wert kopiert [...] \quoteoff Das ist allerdings ein Implementierungsdetail von CPython. In CPython ist alles ein referenzgezählter Zeiger und Kopieren ist intern im Wesentlichen eine Erhöhung des Referenzzählers. Das ist recht ineffizient, weil jede Zahl (Typ int) auf dem Haldenspeicher alloziert wird, oder aber aus einer Tabelle gecacht. Effizienter wäre es, man würde eine Enumeration (tagged union) nutzen, so wie bei Lua. Noch besser, man schrumpft die Enumeration durch Ausnutzung von Nischen ein, so wie bei einigen JavaScript-Implementierungen. Beispielsweise kann man ausnutzen, dass ein Zeiger auf Daten der Ausrichtung vier oder acht zeigt, oder der Adressbereich nur bis zu einem Maximalwert geht, vor allem bei einer Wortgröße von 64 Bit geht das. Im ungenutzten Wertebereich lässt sich dann die Zahl unterbringen. Noch effizientere JavaScript-Implementierungen enthalten sogar eine Optimierungs-Engine, die unnötigen Ballast aus heißen Codepfaden entfernt; eigentlich der allergrößte Unsinn, weil solcherlei in einen Compiler und nicht ins Laufzeitsystem gehört; das bläht nur die Browser auf, die eh schon komplexer sind als einige Betriebssysteme.


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.11, eingetragen 2021-10-20

\quoteon(2021-10-20 14:07 - __blackjack__ in Beitrag No. 9) @tactac: Dann klingt das falsch, denn da wird *immer* das gleiche gemacht, egal ob man eine ganze Zahl oder eine Liste hat, es wird *immer* die Referenz auf das Objekt übergeben/zugewiesen und *nie* ein Wert kopiert den es *in der Sprache* als Typ gäbe. Bei ``a = b`` oder ``frobnicate(b)`` passiert mit `b` immer genau das gleiche — es wird nie der Wert von `b` kopiert, was auch immer `b` für einen Typ hat. \quoteoff Bei einer Zuweisung W = V passiert immer das gleiche: Der Inhalt von V wird nach W kopiert. Bei einem Aufruf frobnicate(b) wird der Inhalt von b an die Funktion übergeben. \quoteon Bei: \sourceon Python a += b \sourceoff ist es der Python-Implementierung total egal was `a` und `b` für Typen haben. Ob das nun Zahlen sind oder Listen, beide Werte werden exakt gleich behandelt. Es sind die Typen selber die, bzw. deren Autoren, entscheiden ob sie veränderbar sind (`list`) oder nicht (`int`) indem sie Methoden zur Verfügung stellen die das Objekt verändern können, oder ausschliesslich solche, die das *nicht* tun. \quoteoff Ich sage doch, dass alles gleich behandelt wird. \quoteon `__iadd__()` von `list` verändert die Liste, und `__iadd__()` von `int` liefert ein neues `int`-Objekt als Ergebnis. \quoteoff int hat keine __iadd__()-Methode. Die wäre nämlich gar nicht wie vorgesehen implementierbar. Bei der Auswertung eines Ausdrucks mit += wird daher nachgeschaut, ob es eine Methode namens __iadd__ beim rechten Operanden überhaupt gibt. \quoteon *Das* ist der beobachtbare Unterschied, der einzig auf immutable vs. immutable zurückzuführen ist. Python selbst kopiert bei Zuweisungen an einfache Namen oder Parameterübergaben nie unaufgefordert Werte. Das muss man als Programmierer immer explizit selbst machen. \quoteoff Sage ich doch: Es werden einfach die Werte kopiert, die eben Referenzen sein können. Es passiert nicht mal dies mal jenes, abhängig davon, der Wert eine Referenz ist oder nicht, ob ein immutable Objekt referenziert wird oder nicht, ... [Die Antwort wurde nach Beitrag No.9 begonnen.]


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.12, eingetragen 2021-10-20

@tactac: Bei ``W = V`` wird in Python eben nicht der ”Inhalt” von V nach W kopiert. Das ist irreführend. Beim Aufruf einer Funktion wird das Argument dem lokalen Namen zugewiesen, das ist also letztlich auch eine Zuweisung, weshalb ich Aufrufe da gleich mit erwähnt habe. Es wird da nicht der Inhalt von `b` übergeben, es sei denn Du willst auf dieser Ebene jetzt plötzlich über Inhalte reden, die es in Python selbst gar nicht gibt, sondern nur unter der Haube bei der Implementierung. `int` hat tatsächlich keine `__iadd__()`-Methode, denn die würde ja nur dass machen, was passiert wenn es keine `__iadd__()`-Methode gibt. Und das könnte sie selbstverständlich tun, denn `__iadd__()` muss das Objekt auf dem es aufgerufen wird *nicht ändern*. Es ist *nicht* vorgesehen, dass das passieren muss, deshalb ist die API von `__iadd__()` auch so, dass das Ergebnis zurückgegeben wird! Also auch wenn `__iadd__()` das Objekt verändert, muss es am Ende doch zurückgegeben werden, sonst wundert man sich warum das Ergebnis `None` ist. \sourceon Python In [190]: class Int(int): ...: def __iadd__(self, other): ...: return Int(self + other) ...: In [191]: a = Int(41) In [192]: a Out[192]: 41 In [193]: a += 1 In [194]: a Out[194]: 42 In [195]: type(a) Out[195]: __main__.Int \sourceoff Wenn es `__iadd__()` als Methode gibt, dann ist ``a += b`` äquivalent zu ``a = a.__iadd__(b)``. Die Zuweisung da passiert tatsächlich und es macht auch Sinn diese Methode auf immutable Datentypen zu implementieren — zum Beispiel wie im Beispiel um dafür zu sorgen, dass da am Ende ein `Int`-Objekt heraus kommt, und kein normales `int`, was sonst das Ergebnis gewesen wäre. Du sagst hier mehrfach, dass Werte kopiert würden und das die manchmal Referenzen wären. Das Problem was ich mit der Aussage habe ist, dass Du hier Implementierung und die Werte die man Python tatsächlich haben kann, vermischst. In Python gibt es keine Referenzen als Datentyp. Und unter der Haube werden *immer* Referenzen verwendet, nicht nur manchmal. Zu dem Einwand von Finn0, dass das ein Implementierungsdetail ist: Eben. Egal wie das unter der Haube gemacht wird, es muss sich oberhalb der Implementierung *immer* so verhalten als wären *alles* Referenzen. Also kann man davon ausgehen es sind alles Referenzen, denn es muss sich letztendlich genau so verhalten. Und man muss dann auch nicht verwirren mit so Aussagen, dass bei Listen Referenzen verwendet werden, und bei anderen Objekten vielleicht nicht. Warum sich das Bild was man zum Verständnis der Sprache malt, unnötig mit Komplikationen füllen, die letztlich keine Auswirkungen haben (dürfen)‽


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.13, eingetragen 2021-10-21

\(\begingroup\)\(\newcommand{\sem}[1]{[\![#1]\!]} \newcommand{\name}[1]{\ulcorner#1\urcorner} \newcommand{\upamp}{\mathbin {⅋}}\) \quoteon(2021-10-20 22:05 - __blackjack__ in Beitrag No. 12) @tactac: Bei ``W = V`` wird in Python eben nicht der ”Inhalt” von V nach W kopiert. Das ist irreführend. Beim Aufruf einer Funktion wird das Argument dem lokalen Namen zugewiesen, das ist also letztlich auch eine Zuweisung, weshalb ich Aufrufe da gleich mit erwähnt habe. Es wird da nicht der Inhalt von `b` übergeben, es sei denn Du willst auf dieser Ebene jetzt plötzlich über Inhalte reden, die es in Python selbst gar nicht gibt, sondern nur unter der Haube bei der Implementierung. \quoteoff Was soll denn sonst übergeben werden, wenn nicht der Inhalt der Variable? Die Variable selbst kann ja nicht übergeben werden. Und ja, bei einem Aufruf wird im Endeffekt der dann lokalen Variablen ein Wert zugeordnet (der ggf. Inhalt einer anderen Variablen ist, aber das ist egal), ist also im Endeffekt eine Zuweisung. "Inhalt" ist ein ganz normales Wort für das, was eine Variable enthält. (Man kann natürlich auch "Wert" der Variable sagen.) Sodass man z.B. forumulieren kann: "Die Auswertung eines Ausdruck der Form V ergibt den Inhalt von V." Vielleicht hilft dir ein Blick in soetwas wie Static Value Analysis of Python Programs by Abstract Interpretation. Da wird in Abschnitt 2.2 die Python-Semantik (naja, ein großer Teil davon) wie für solche Sprachen recht üblich modelliert. Teilzitat: $$\begin{array}{ll} \mathbf{\mathcal E} := \mathbf{Id}\rightharpoonup \mathbf{Val} & \text {Variablenumgebung}\\ \mathbf{\mathcal H} := \mathbf{Addr}\rightharpoonup \mathbf{Obj} & \text {"Heap"}\\ \mathbf{Obj} := string \rightharpoonup \mathbf{Val} & \text {ganz simple Modellierung von "Objekten"}\\ \mathbf{Val} := \mathbb Z \cup string \cup \{\mathrm{True,False,None,NotImpl,Undef}\}\cup \mathbf{Addr} & \text {"Werte"; das was (u.a.) in Variablen drin sein kann.} \end{array}$$ Mit "Implementierung" hat das weniger zu tun als mit der Semantik.\(\endgroup\)


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.14, eingetragen 2021-10-21

Ich habe ein massives Problem mit „Inhalt der Variablen“, weil das suggeriert in einer Variablen wäre etwas drin (was es in Python und nicht nur in der Implementierung) gibt. Wenn man tatsächlich den Inhalt einer Variablen in Python beschreiben will, dann landet man bei einem Datentyp in der Implementierung, auf den man in Python selbst gar keinen Zugriff hat. Und das führt zu Beschreibungen die viel zu umständlich sind und Unterschiede beschreiben, die in Python selbst gar nicht bestehen. In Python kann man sich Namen als Post-It-Zettel vorstellen, die an Objekte geklebt werden. Und nicht als Namen die auf Boxen (Speicherbereichen) kleben, in die Objekte hinein getan werden. Letzteres verbinde ich mit dem Begriff ”Inhalt einer Variablen” — das was in so einer Box drin liegt, wo ein Name drauf klebt. Und in der Box muss etwas drin liegen was es als Typ in der *Sprache* gibt, nicht etwas was es als Typ nur in der Implementierung gibt. Das Teilzitat hat sehr wohl etwas mit Implementierung zu tun, denn dort gibt es einen Heap und Addr(essen), die es in Python so nicht gibt. Das dort beschreibt eine mögliche Implementierung. Und zwar nicht die von CPython, denn dort wäre Val einfach nur Addr, denn Zahlen, Zeichenketten, Wahrheitswerte, und `None` sind keine besonderen Werte die an der Stelle anders implementiert wären als die ganzen anderen Objekte. Einzig `Undef` wäre noch drin, denn den Zustand können intern lokale Namen haben, statt an ein Objekt gebunden zu sein.


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.15, eingetragen 2021-10-23

\quoteon(2021-10-21 14:02 - __blackjack__ in Beitrag No. 14) Ich habe ein massives Problem mit „Inhalt der Variablen“, weil das suggeriert in einer Variablen wäre etwas drin (was es in Python und nicht nur in der Implementierung) gibt. Wenn man tatsächlich den Inhalt einer Variablen in Python beschreiben will, dann landet man bei einem Datentyp in der Implementierung, auf den man in Python selbst gar keinen Zugriff hat. Und das führt zu Beschreibungen die viel zu umständlich sind und Unterschiede beschreiben, die in Python selbst gar nicht bestehen. \quoteoff Es ist ganz einfach: Die Inhalte von Variablen (und auch von Listenelementen und ähnlichem) sind kleine ints, boolesche Werte, oder ähnlich kleines, wie etwa "Adressen", die ggf. auf weiteres verweisen. Keine Variable hat als Inhalt eine Liste oder ähnliches. \quoteon In Python kann man sich Namen als Post-It-Zettel vorstellen, die an Objekte geklebt werden. Und nicht als Namen die auf Boxen (Speicherbereichen) kleben, in die Objekte hinein getan werden. Letzteres verbinde ich mit dem Begriff ”Inhalt einer Variablen” — das was in so einer Box drin liegt, wo ein Name drauf klebt. \quoteoff Naja, das ist eben falsch. In Python sind Referenzen auf vielleicht vorhandenen anderen Kram vollwertige Werte, die man in Variablen und Listenelementen etc. ablegen kann. "Namen die auf Objekte geklebt werden" und "Namen, die auf Boxen geklebt werden" ist verkehrtherum. \quoteon Das Teilzitat hat sehr wohl etwas mit Implementierung zu tun, denn dort gibt es einen Heap und Addr(essen), die es in Python so nicht gibt. \quoteoff Du hast offenbar keinen Plan. Wenn man die Semantik einer Programmiersprache definieren will, ist man natürlich nicht darauf angewiesen, nur Dinge zu verwenden, die es in der Programmiersprache gibt -- was allein schon die Frage aufwürfe, was jemand damit sagen will. In grauer Vorzeit war es mal üblich, Interpreter oder Compiler für L in L hinzuschreiben, um zumindest Teile der Semantik zu spezifizieren; das ist leider aus der Mode geraten. Und dass PyPy und CPython Probleme haben, einander zu interpretieren, ist natürlich auch recht doof. \quoteon Das dort beschreibt eine mögliche Implementierung. Und zwar nicht die von CPython, denn dort wäre Val einfach nur Addr, denn Zahlen, Zeichenketten, Wahrheitswerte, und `None` sind keine besonderen Werte die an der Stelle anders implementiert wären als die ganzen anderen Objekte. Einzig `Undef` wäre noch drin, denn den Zustand können intern lokale Namen haben, statt an ein Objekt gebunden zu sein. \quoteoff Eine mögliche Implementierung zumindest in Pseudocode zu haben, ist ja nichts schlimmes. Es ist besser als nichts, und ECMA 334 und ECMA 262 leisten zumindest dies. Etwas ähnliches für Python existiert m.E. nicht, und darum erzählen sich Python-Hacker oft gegenseitig komischen Unsinn.


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.16, eingetragen 2021-10-23

@tactac Du machst schon wieder einen Unterschied zwischen Typen deren Werte klein genug sind um irgendwo rein zu passen und beispielsweise Listen. Was bezüglich der Implementierung von CPython falsch ist, denn dort werden kleine Ints, Wahrheitswerte, usw. überhaupt nicht anders behandelt als Listen. Deshalb ist das unnötig kompliziert wenn man jemandem die Semantik von Python erklären will, warum man manche Objekte verändern kann, und andere nicht. Und das liegt einzig und allein daran ob der Typ Operationen definiert, die eine Veränderung erlauben oder nicht. Zahlen tun das nicht, Listen schon.


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.17, eingetragen 2021-11-06 01:48

\quoteon(2021-10-23 08:43 - __blackjack__ in Beitrag No. 16) @tactac Du machst schon wieder einen Unterschied zwischen Typen deren Werte klein genug sind um irgendwo rein zu passen und beispielsweise Listen. Was bezüglich der Implementierung von CPython falsch ist, denn dort werden kleine Ints, Wahrheitswerte, usw. überhaupt nicht anders behandelt als Listen. \quoteoff Hä? Wenigstens zwecks Optimierung spielt das natürlich eine Rolle. \quoteon Deshalb ist das unnötig kompliziert wenn man jemandem die Semantik von Python erklären will, warum man manche Objekte verändern kann, und andere nicht. Und das liegt einzig und allein daran ob der Typ Operationen definiert, die eine Veränderung erlauben oder nicht. Zahlen tun das nicht, Listen schon. \quoteoff Es ist unnötig kompliziert, von "Referenztypen" und "Übergabe per Referenz" etc. zu sprechen, weil man das ganze auch so modellieren kann, dass #immer# nur Referenzen herumgereicht werden. Und wie ganz eingangs gesagt, hat das nichts damit zu tun, ob es sich um "immutable" vll. eigentlich gemeinte "Werte" handelt. Referenzen sind in Python (aber natürlich nicht nur dort) ein fundamentales Phänomen.


   Profil
Red_
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 28.09.2016
Mitteilungen: 984
  Beitrag No.18, vom Themenstarter, eingetragen 2021-11-08 23:18

Ich habe jetzt nicht sooo viel verstanden worüber ihr schreibt, aber wenn Referenzen übergeben werden, was genau passiert, wenn ich eine immutables Objekt verändern will? \sourceon nameDerSprache x = 2 y = x y += 1 \sourceoff So wie ich das verstanden habe zeigt x auf einen Ort, wo 2 gespeichert ist. y zeigt jetzt auf den selben Ort, weil 'y = x' einfach die Referenz übergibt. So weit stimmt es? Bei 'y = x + 1' wird ein neuer Ort mit dem Wert 3 erstellt und y zeit jetzt dahin? Wenn ja, was genau passiert da? Denn 'y = x + 0' würde dann theoretisch ja auch einen neuen Ort mit dem Integer 2 erstellen und y würde drauf zeigen. Jetzt gibt es zwei Orte mit 2, ist das praktisch?


   Profil
Scynja
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.02.2011
Mitteilungen: 467
Wohnort: Deutschland
  Beitrag No.19, eingetragen 2021-11-08 23:39

Immutable (unveränderliche) Objekte kann man per Definition nicht ändern. Je nach Sprache bekommst du eine Runtime- oder Compile-Exeption. Beispiel: \sourceon unbekannt immutable List IL = List.of(3,5,7,11) IL.add(2) // -> Fehler // das geht aber: IL = List.of(2,3,5,7,11) // oder das: immutable List IL2 = IL \sourceoff Im vorletzten Fall wird das erste Objekt weggeworfen / dereferenziert und ein neues erstellt. Die Referenz der Variable wird dann auf das neue Objekt gesetzt. Im letzten Fall zeigen einfach zwei Pointer auf das gleiche Objekt.


   Profil
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2275
  Beitrag No.20, eingetragen 2021-11-08 23:45

\(\begingroup\)\(\newcommand{\sem}[1]{[\![#1]\!]} \newcommand{\name}[1]{\ulcorner#1\urcorner} \newcommand{\upamp}{\mathbin {⅋}}\) \quoteon(2021-11-08 23:18 - Red_ in Beitrag No. 18) Ich habe jetzt nicht sooo viel verstanden worüber ihr schreibt, aber wenn Referenzen übergeben werden, was genau passiert, wenn ich eine immutables Objekt verändern will? \sourceon nameDerSprache x = 2 y = x y += 1 \sourceoff So wie ich das verstanden habe zeigt x auf einen Ort, wo 2 gespeichert ist. y zeigt jetzt auf den selben Ort, weil 'y = x' einfach die Referenz übergibt. So weit stimmt es? \quoteoff Bei den üblichen Implementierungen stimmt es nicht. Kleine Zahlen sind direkt in den Variablen enthalten. Man könnte es aber dennoch auch für kleine Zahlen so implementieren (bei großen ist es ohnehin so -- deshalb belegt x = 256**(10**8); a = [x]*(10**8) nicht ungefähr $10^{16}$ Bytes Speicher, sondern größenordnugsmäßig vll. 500MB). Ich gehe im folgenden mal davon aus, es sei so, dass auch kleine Zahlen nicht direkt in Variablen gehalten werden. Nichts destro trotz sind Zahlen immutable -- man kann sie nicht verändern. Auch wenn x nur eine Referenz auf eine Zahl enthalten würde und y eine Kopie dieser Referenz, bleiben Zahlen immer unverändert -- im Gegensatz zu zum Beispiel Listen. \quoteon Bei 'y = x + 1' wird ein neuer Ort mit dem Wert 3 erstellt und y zeit jetzt dahin? Wenn ja, was genau passiert da? Denn 'y = x + 0' würde dann theoretisch ja auch einen neuen Ort mit dem Integer 2 erstellen und y würde drauf zeigen. Jetzt gibt es zwei Orte mit 2, ist das praktisch? \quoteoff Ja, wenn man auf die Optimierung verzichten würde, kleine Zahlen direkt in den Variablen zu halten (und auf eine Optimierung des +, das im Fall der Addition einer 0 die andere Zahl wiederverwendet), wäre es so. Es ist zwar nicht schön, viele Integer mit dem Wert 2 zu erzeugen, aber die Alternative wäre, bei jeder Rechnung hinterher zu suchen, ob irgendwo schon ein Integer mit dem Ergebnis-Wert herumliegt, und stattdessen dieses zu referenzieren. Das ist zu aufwändig und "in den meisten Fällen" würde die Suche ohnehin erfolglos enden. [Die Antwort wurde nach Beitrag No.18 begonnen.]\(\endgroup\)


   Profil
Red_
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 28.09.2016
Mitteilungen: 984
  Beitrag No.21, vom Themenstarter, eingetragen 2021-11-09 10:59

Ahh okay, das ist einleuchtend, vielen Dank tactac! Jetzt habe ich noch eine aller letzte Frage, die noch immer zu dem Thema passt :D Ich hatte vor Kurzem ein Programm, wo eine Variable 'x' eine Liste war, wobei die Elemente der Liste wieder Listen waren - etwa [[1, 2], [3, 4]]. Als ich eine Kopie 'y = x.copy()' erstellen wollte und die Listen innerhalb 'y' verändern wollte, haben die von x sich mit verändert. Ich als Anfänger habe nur gesehen ich bekomme nicht das, was ich will. Nach längerem überlegen habe ich verstanden, wo das Problem lag und hatte dann einfach 'y = [i.copy() for i in x]' gesetzt. Ich erkläre mir das Problem so, dass Listen wie folgt funktionieren: Eine Liste der Form x = [a, b, c] erzeugt die a, b und c irgendwo im Speicher und x hat dann sozusagen drei Zeiger, einmal auf a, auf b und auf c (von x gehen drei ''nummerierte'' Pfeile weg). Im obigen Fall habe ich zwar eine Kopie erstellt, aber die Einträge haben noch immer die selbe Referenzen, s.d. das Ändern des einen auch das Ändern des anderen bewirkt. Stimmt meine Anschauung? Wo kann ich diese Funktionsweise von Objekten genauer nachlesen/anschauen (aber bitte nicht so tief in die Materie, oberflächlich reicht)? Pass by value/reference/object ist vielleicht der richtige Suchbegriff.


   Profil
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 81
  Beitrag No.22, eingetragen 2021-11-09 13:25

@Red_ Es stimmt fast, weil das Ändern des Einen nicht auch das Andere ändert, denn es gibt da nicht das Eine und das Andere, das ist beides das Selbe. Es gibt zwei Wege um an das selbe Objekt zu kommen, und wenn man das Objekt verändert, ist diese Veränderung über jeden Weg über den das Objekt erreichbar ist, sichtbar. Lesetipp: Facts and myths about Python names and values


   Profil
Red_
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 28.09.2016
Mitteilungen: 984
  Beitrag No.23, vom Themenstarter, eingetragen 2021-11-09 21:03

Sehr schön gesagt, danke dir und den anderen sehr! Ihr habt ein sehr fundiertes Wissen auf dem Gebiet! 👍 Edit: Und sehr schöner Link im letzten Beitrag!!


   Profil
Red_ hat die Antworten auf ihre/seine Frage gesehen.
Red_ hat selbst das Ok-Häkchen gesetzt.

Wechsel in ein anderes Forum:
 Suchen    
 
All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2001-2021 by Matroids Matheplanet
This web site was originally made with PHP-Nuke, a former web portal system written in PHP that seems no longer to be maintained nor supported. PHP-Nuke is Free Software released under the GNU/GPL license.
Ich distanziere mich von rechtswidrigen oder anstößigen Inhalten, die sich trotz aufmerksamer Prüfung hinter hier verwendeten Links verbergen mögen.
Lesen Sie die Nutzungsbedingungen, die Distanzierung, die Datenschutzerklärung und das Impressum.
[Seitenanfang]