Pythonの可変オブジェクトと不変オブジェクト–ビジュアルおよびハンズオンガイド

Pythonは素晴らしい言語です。その単純さのために、多くの人々はそれを最初のプログラミング言語として選択します。

経験豊富なプログラマーも、その幅広いコミュニティ、豊富なパッケージ、明確な構文のおかげで、常にPythonを使用しています。

しかし、初心者だけでなく経験豊富な開発者も混乱させるように思われる問題が1つあります。それは、Pythonオブジェクトです。具体的には、可変オブジェクトと不変オブジェクトの違いです。

この投稿では、Pythonオブジェクトの知識を深め、可変オブジェクトと不変オブジェクトの違いを学び、インタープリターを使用してPythonの動作をよりよく理解する方法を学びます。

私たちは、次のような重要な機能とキーワードを使用するidis、私たちは違いを理解するだろうx == yとしx is y

あなたはそれを望んでいますか?始めましょう。

Pythonでは、すべてがオブジェクトです

言語オブジェクトをサポートする他のプログラミング言語とは異なり、Pythonでは、整数、リスト、さらには関数を含め、実際にはすべてがオブジェクトです。

インタプリタを使用して、次のことを確認できます。

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

Pythonには、idメモリ内のオブジェクトのアドレスを返す組み込み関数、があります。例えば:

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

上記では、という名前のオブジェクトを作成しx、それに値を割り当てました1。次にid(x)、このオブジェクトが1470416816メモリ内のアドレスにあることを使用して発見しました。

これにより、Pythonの興味深い点を確認できます。Pythonで2つの変数を作成し(1つはの名前でx、もう1つはの名前で)、yそれらに同じ値を割り当てるとします。たとえば、ここで:

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

等式演算子(==)を使用して、Pythonの目には実際に同じ値があることを確認できます。

>>> x == y True

しかし、これらはメモリ内の同じオブジェクトですか?理論的には、ここには2つの非常に異なるシナリオがあります。

シナリオ(1)によると、実際には2つの異なるオブジェクトがあります。1つは、という名前でx、もう1つは、という名前で、yたまたま同じ値を持っています。

ただし、シナリオ(2)に示すように、Pythonが実際にここに格納するオブジェクトは1つだけであり、それを参照する2つの名前が付いている場合もあります。

id上記で紹介した関数を使用して、これを確認できます。

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

ご覧のとおり、Pythonの動作は上記のシナリオ(1)と一致します。関わらずx == y(つまり、この例ではxy同じ有する)、彼らは、メモリ内の異なるオブジェクトです。これはid(x) != id(y)、明示的に確認できるように、次の理由によるものです。

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

上記の比較を行うためのより短い方法があり、それはPythonのis演算子を使用することです。チェックx is yと同じかどうかのチェックid(x) == id(y)。つまりx、とyがメモリ内の同じオブジェクトであるかどうかを確認します。

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

これにより、等式演算子==と単位元演算子の重要な違いが明らかになりisます。

あなたは上記の例でわかるように、それはPythonで2名には完全に可能である(xy)2つの異なるオブジェクトにバインドする(したがって、x is yあるFalse)、これら2つのオブジェクトが同じ値を持っているところ(そうx == yですTrue)。

指しているのと同じオブジェクトをx指す別の変数を作成するにはどうすればよいですか?次のように、代入演算子を簡単に使用できます=

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

それらが実際に同じオブジェクトを指していることを確認するには、次のis演算子を使用できます。

>>> x is z True

もちろん、これは、以下を使用して明示的に確認できるため、メモリ内に同じアドレスがあることを意味しますid

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

そしてもちろん、それらは同じ値を持っているので、私たちは同様x == zに戻ることを期待してTrueいます:

>>> x == z True

Pythonの可変および不変オブジェクト

We have said that everything in Python is an object, yet there is an important distinction between objects. Some objects are mutable while some are immutable.

As I mentioned before, this fact causes confusion for many people who are new to Python, so we are going to make sure it's clear.

Immutable objects in Python

For some types in Python, once we have created instances of those types, they never change. They are immutable.

For example, int objects are immutable in Python. What will happen if we try to change the value of an int object?

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

Well, it seems that we changed x successfully. This is exactly where many people get confused. What exactly happened under the hood here? Let's use id to further investigate:

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

So we can see that by assigning x = 24602, we didn't change the value of the object that x had been bound to before. Rather, we created a new object, and bound the name x to it.

So after assigning 24601 to x by using x = 24601, we had the following state:

And after using x = 24602, we created a new object, and bound the name x to this new object. The other object with the value of 24601 is no longer reachable by x (or any other name in this case):

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.