Veränderbare und unveränderliche Objekte in Python - Eine visuelle und praktische Anleitung

Python ist eine großartige Sprache. Aufgrund seiner Einfachheit wählen viele Leute es als ihre erste Programmiersprache.

Erfahrene Programmierer verwenden Python dank seiner breiten Community, der Fülle an Paketen und der klaren Syntax ebenfalls ständig.

Aber es gibt ein Problem, das Anfänger und einige erfahrene Entwickler zu verwirren scheint: Python-Objekte. Insbesondere der Unterschied zwischen veränderlichen und unveränderlichen Objekten.

In diesem Beitrag werden wir unser Wissen über Python-Objekte vertiefen, den Unterschied zwischen veränderlichen und unveränderlichen Objekten kennenlernen und sehen, wie wir den Interpreter verwenden können , um die Funktionsweise von Python besser zu verstehen.

Wir werden wichtige Funktionen und Schlüsselwörter wie idund verwenden isund den Unterschied zwischen x == yund verstehen x is y.

Bist du dabei? Lass uns anfangen.

In Python ist alles ein Objekt

Im Gegensatz zu anderen Programmiersprachen, in denen die Sprache Objekte unterstützt , ist in Python wirklich alles ein Objekt - einschließlich Ganzzahlen, Listen und sogar Funktionen.

Wir können unseren Dolmetscher verwenden, um Folgendes zu überprüfen:

>>> isinstance(1, object) True >>> isinstance(False, object) True def my_func(): return "hello" >>> isinstance(my_func, object) True

Python verfügt über eine integrierte Funktion, iddie die Adresse eines Objekts im Speicher zurückgibt. Zum Beispiel:

>>> x = 1 >>> id(x) 1470416816

Oben haben wir ein Objekt mit dem Namen erstellt xund ihm den Wert von zugewiesen 1. Wir haben dann verwendet id(x)und festgestellt, dass dieses Objekt an der Adresse 1470416816im Speicher gefunden wird.

Dies ermöglicht es uns, interessante Dinge über Python zu überprüfen. Angenommen, wir erstellen in Python zwei Variablen - eine mit dem Namen xund eine mit dem Namen y- und weisen ihnen denselben Wert zu. Zum Beispiel hier:

>>> x = "I love Python!" >>> y = "I love Python!"

Wir können den Gleichheitsoperator ( ==) verwenden, um zu überprüfen, ob sie in Pythons Augen tatsächlich denselben Wert haben:

>>> x == y True

Aber sind das die gleichen Objekte im Gedächtnis? Theoretisch kann es hier zwei sehr unterschiedliche Szenarien geben.

Gemäß Szenario (1) haben wir wirklich zwei verschiedene Objekte, eines mit dem Namen xund eines mit dem Namen y, die zufällig denselben Wert haben.

Es kann jedoch auch vorkommen, dass Python hier tatsächlich nur ein Objekt speichert, auf das zwei Namen verweisen - wie in Szenario (2) gezeigt :

Wir können die idoben eingeführte Funktion verwenden, um dies zu überprüfen:

>>> x = "I love Python!" >>> y = "I love Python!" >>> x == y True >>> id(x) 52889984 >>> id(y) 52889384

Wie wir sehen können, stimmt das Verhalten von Python mit dem oben beschriebenen Szenario (1) überein. Auch wenn x == yin diesem Beispiel (das heißt, xund yhat die gleichen Werte ), sie sind verschiedene Objekte im Speicher. Dies liegt daran id(x) != id(y), wie wir explizit überprüfen können:

>>> id(x) == id(y) False

Es gibt einen kürzeren Weg, um den obigen Vergleich durchzuführen, und zwar den Python- isOperator. x is yPrüfen id(x) == id(y), ob dies mit Prüfen identisch ist , dh ob xund ydasselbe Objekt im Speicher sind:

>>> x == y True >>> id(x) == id(y) False >>> x is y False

Dies beleuchtet den wichtigen Unterschied zwischen dem Gleichheitsoperator ==und dem Identitätsoperator is.

Wie Sie im obigen Beispiel sehen können, können zwei Namen in Python ( xund y) vollständig an zwei verschiedene Objekte gebunden werden (und sind x is yes auch False), wobei diese beiden Objekte den gleichen Wert haben (so x == yist True).

Wie können wir eine andere Variable erstellen, die auf dasselbe Objekt zeigt, auf xdas sie zeigt? Wir können einfach den Zuweisungsoperator verwenden =, wie folgt:

>>> x = "I love Python!" >>> z = x

Um zu überprüfen, ob sie tatsächlich auf dasselbe Objekt verweisen, können wir den isOperator verwenden:

>>> x is z True

Dies bedeutet natürlich, dass sie dieselbe Adresse im Speicher haben, wie wir explizit überprüfen können, indem wir Folgendes verwenden id:

>>> id(x) 54221824 >>> id(z) 54221824

Und natürlich haben sie den gleichen Wert, daher erwarten wir auch eine x == zRückkehr True:

>>> x == z True

Veränderbare und unveränderliche Objekte in Python

Wir haben gesagt, dass alles in Python ein Objekt ist, aber es gibt einen wichtigen Unterschied zwischen Objekten. Einige Objekte sind veränderlich, während andere unveränderlich sind .

Wie ich bereits erwähnt habe, führt diese Tatsache bei vielen Leuten, die Python noch nicht kennen, zu Verwirrung. Wir werden also sicherstellen, dass es klar ist.

Unveränderliche Objekte in Python

Bei einigen Typen in Python ändern sich die Instanzen dieser Typen nie, sobald wir sie erstellt haben. Sie sind unveränderlich .

Beispielsweise sind intObjekte in Python unveränderlich. Was passiert, wenn wir versuchen, den Wert eines intObjekts zu ändern ?

>>> x = 24601 >>> x 24601 >>> x = 24602 >>> x 24602

Nun, es scheint, dass wir uns xerfolgreich verändert haben . Genau hier werden viele Menschen verwirrt. Was genau ist hier unter der Haube passiert? Lassen Sie uns idweiter untersuchen:

>>> x = 24601 >>> x 24601 >>> id(x) 1470416816 >>> x = 24602 >>> x 24602 >>> id(x) 1470416832

Wir können also sehen, dass wir durch Zuweisen x = 24602den Wert des xzuvor gebundenen Objekts nicht geändert haben. Vielmehr haben wir ein neues Objekt erstellt und den Namen xdaran gebunden .

So , nachdem die Zuordnung 24601zu xunter Verwendung x = 24601hatten wir den folgenden Zustand:

Nach der Verwendung x = 24602haben wir ein neues Objekt erstellt und den Namen xan dieses neue Objekt gebunden . Das andere Objekt mit dem Wert von 24601ist nicht mehr erreichbar über x(oder einen anderen Namen in diesem Fall):

Whenever we assign a new value to a name (in the above example - x) that is bound to an int object, we actually change the binding of that name to another object.

The same applies for tuples, strings (str objects), and bools as well. In other words, int (and other number types such as float), tuple, bool, and str objects are immutable.

Let's test this hypothesis. What happens if we create a tuple object, and then give it a different value?

>>> my_tuple = (1, 2, 3) >>> id(my_tuple) 54263304 >>> my_tuple = (3, 4, 5) >>> id(my_tuple) 56898184

Just like an int object, we can see that our assignment actually changed the object that the name my_tuple is bound to.

What happens if we try to change one of the tuple's elements?

>>> my_tuple[0] = 'a new value' Traceback (most recent call last): File "", line 1, in  TypeError: 'tuple' object does not support item assignment

As we can see, Python doesn't allow us to modify my_tuple's contents, as it is immutable.

Mutable objects in Python

Some types in Python can be modified after creation, and they are called mutable. For example, we know that we can modify the contents of a list object:

>>> my_list = [1, 2, 3] >>> my_list[0] = 'a new value' >>> my_list ['a new value', 2, 3]

Does that mean we actually created a new object when assigning a new value to the first element of my_list? Again, we can use id to check:

>>> my_list = [1, 2, 3] >>> id(my_list) 55834760 >>> my_list [1, 2, 3] >>> my_list[0] = 'a new value' >>> id(my_list) 55834760 >>> my_list ['a new value', 2, 3]

So our first assignment my_list = [1, 2, 3] created an object in the address 55834760, with the values of 1, 2, and 3:

We then modified the first element of this list object using my_list[0] = 'a new value', that is - without creating a new list object:

Now, let us create two names – x and y, both bound to the same list object. We can verify that either by using is, or by explicitly checking their ids:

>>> x = y = [1, 2] >>> x is y True >>> id(x) 18349096 >>> id(y) 18349096 >>> id(x) == id(y) True

What happens now if we use x.append(3)? That is, if we add a new element (3) to the object by the name of x?

Will x by changed? Will y?

Well, as we already know, they are basically two names of the same object:

Since this object is changed, when we check its names we can see the new value:

>>> x.append(3) >>> x [1, 2, 3] >>> y [1, 2, 3]

Note that x and y have the same id as before – as they are still bound to the same list object:

>>> id(x) 18349096 >>> id(y) 18349096

In addition to lists, other Python types that are mutable include sets and dicts.

Implications for dictionary keys in Python

Dictionaries (dict objects) are commonly used in Python. As a quick reminder, we define them like so:

my_dict = {"name": "Omer", "number_of_pets": 1}

We can then access a specific element by its key name:

>>> my_dict["name"] 'Omer'

Dictionaries are mutable, so we can change their content after creation. At any given moment, a key in the dictionary can point to one element only:

>>> my_dict["name"] = "John" >>> my_dict["name"] 'John'

It is interesting to note that a dictionary's keys must be immutable:

>>> my_dict = {[1,2]: "Hello"} Traceback (most recent call last): File "", line 1, in  TypeError: unhashable type: 'list'

Why is that so?

Let's consider the following hypothetical scenario (note: the snippet below can't really be run in Python):

>>> x = [1, 2] >>> y = [1, 2, 3] >>> my_dict = {x: 'a', y: 'b'}

So far, things don't seem that bad. We'd assume that if we access my_dict with the key of [1, 2], we will get the corresponding value of 'a', and if we access the key [1, 2, 3], we will get the value 'b'.

Now, what would happen if we attempted to use:

>>> x.append(3)

In this case, x would have the value of [1, 2, 3], and y would also have the value of [1, 2, 3]. What should we get when we ask for my_dict[[1, 2, 3]]? Will it be 'a' or 'b'? To avoid such cases, Python simply doesn't allow dictionary keys to be mutable.

Taking things a bit further

Let's try to apply our knowledge to a case that is a bit more interesting.

Below, we define a list (a mutable object) and a tuple (an immutable object). The list includes a tuple, and the tuple includes a list:

>>> my_list = [(1, 1), 2, 3] >>> my_tuple = ([1, 1], 2, 3) >>> type(my_list)  >>> type(my_list[0])  >>> type(my_tuple)  >>> type(my_tuple[0]) 

So far so good. Now, try to think for yourself – what will happen when we try to execute each of the following statements?

(1) >>> my_list[0][0] = 'Changed!'

(2) >>> my_tuple[0][0] = 'Changed!'

In statement (1), what we are trying to do is change my_list's first element, that is, a tuple. Since a tuple is immutable, this attempt is destined to fail:

>>> my_list[0][0] = 'Changed!' Traceback (most recent call last): File "", line 1, in  TypeError: 'tuple' object does not support item assignment

Note that what we were trying to do is not change the list, but rather – change the contents of its first element.

Let's consider statement (2). In this case, we are accessing my_tuple's first element, which happens to be a list, and modify it. Let's further investigate this case and look at the addresses of these elements:

>>> my_tuple = ([1, 1], 2, 3) >>> id(my_tuple) 20551816 >>> type(my_tuple[0])  >>> id(my_tuple[0]) 20446248

When we change my_tuple[0][0], we do not really change my_tuple at all! Indeed, after the change, my_tuple's first element will still be the object whose address in memory is 20446248. We do, however, change the value of that object:

>>> my_tuple[0][0] = 'Changed!' >>> id(my_tuple) 20551816 >>> id(my_tuple[0]) 20446248 >>> my_tuple (['Changed!', 1], 2, 3)

Since we only modified the value of my_tuple[0], which is a mutable list object, this operation was indeed allowed by Python.

Recap

In this post we learned about Python objects. We said that in Python everything is an object, and got to use id and is to deepen our understanding of what's happening under the hood when using Python to create and modify objects.

We also learned the difference between mutable objects, that can be modified after creation, and immutable objects, which cannot.

We saw that when we ask Python to modify an immutable object that is bound to a certain name, we actually create a new object and bind that name to it.

We then learned why dictionary keys have to be immutable in Python.

Understanding how Python "sees" objects is a key to becoming a better Python programmer. I hope this post has helped you on your journey to mastering Python.

Omer Rosenbaum, Swimm’s Chief Technology Officer. Cyber training expert and Founder of Checkpoint Security Academy. Author of Computer Networks (in Hebrew). Visit My YouTube Channel.