Maināmi vai nemaināmi objekti Python - vizuāla un praktiska rokasgrāmata

Python ir lieliska valoda. Tā vienkāršības dēļ daudzi cilvēki to izvēlas kā pirmo programmēšanas valodu.

Pieredzējuši programmētāji arī izmanto Python visu laiku, pateicoties tā plašajai kopienai, pakešu pārpilnībai un skaidrai sintaksei.

Bet ir viens jautājums, kas, šķiet, sajauc iesācējus, kā arī dažus pieredzējušus izstrādātājus: Python objekti. Konkrēti, atšķirība starp maināmiem un nemainīgiem objektiem.

Šajā ierakstā mēs padziļināsim zināšanas par Python objektiem, uzzināsim atšķirību starp maināmiem un nemainīgiem objektiem un redzēsim, kā mēs varam izmantot tulku, lai labāk izprastu, kā Python darbojas.

Mēs izmantosim svarīgas funkcijas un atslēgvārdus, piemēram, idun is, un mēs sapratīsim atšķirību starp x == yun x is y.

Vai esat gatavs tam? Sāksim.

Pitonā viss ir objekts

Atšķirībā no citām programmēšanas valodām, kurās valoda atbalsta objektus, Pitonā viss ir objekts - ieskaitot veselus skaitļus, sarakstus un pat funkcijas.

Mēs varam izmantot savu tulku, lai pārbaudītu, vai:

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

Python ir iebūvēta funkcija, idkas atgriež atmiņā esošā objekta adresi. Piemēram:

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

Iepriekš mēs izveidojām objektu ar nosaukumu xun piešķiram tam vērtību 1. Pēc tam mēs izmantojām id(x)un atklājām, ka šis objekts atrodas adresē, kas 1470416816atrodas atmiņā.

Tas ļauj mums pārbaudīt interesantas lietas par Python. Pieņemsim, ka mēs Python izveidojam divus mainīgos - vienu ar vārdu xun otru pēc nosaukuma y- un piešķiram tiem tādu pašu vērtību. Piemēram, šeit:

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

Mēs varam izmantot vienlīdzības operatoru ( ==), lai pārbaudītu, vai viņiem patiešām ir vienāda vērtība Python acīs:

>>> x == y True

Bet vai atmiņā šie ir vieni un tie paši objekti? Teorētiski šeit var būt divi ļoti atšķirīgi scenāriji.

Saskaņā ar (1) scenāriju mums patiešām ir divi dažādi objekti, vienam ar nosaukumu xun otram ar nosaukumu y, kuriem vienkārši ir vienāda vērtība.

Tomēr, tas varētu būt arī gadījums, ka Python faktiski veikali šeit tikai viens objekts, kas ir divi vārdi, ka atsauces tā - kā parādīts scenāriju (2) :

idLai to pārbaudītu, mēs varam izmantot iepriekš ieviesto funkciju:

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

Tātad, kā mēs redzam, Python uzvedība atbilst iepriekš aprakstītajam scenārijam (1). Pat ja x == yšajā piemērā (tas ir, xun ytām ir vienādas vērtības ), tie atmiņā ir dažādi objekti. Tas ir tāpēc id(x) != id(y), ka mēs varam skaidri pārbaudīt:

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

Iepriekš minētajam salīdzinājumam ir īsāks veids, proti, izmantot Python isoperatoru. Pārbaude, vai tas x is yir tas pats, kas pārbaudīt id(x) == id(y), kas nozīmē, vai atmiņā ir viens xun ytas pats objekts:

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

Tas atklāj svarīgo atšķirību starp vienlīdzības operatoru ==un identitātes operatoru is.

Kā redzat iepriekš redzamajā piemērā, ir pilnīgi iespējams, ka divi nosaukumi Python ( xun y) ir saistīti ar diviem dažādiem objektiem (un tādējādi arī x is yir False), kur šiem diviem objektiem ir vienāda vērtība (tā x == yir True).

Kā mēs varam izveidot citu mainīgo, kas norāda uz to pašu objektu, kas xnorāda? Mēs varam vienkārši izmantot piešķiršanas operatoru =, piemēram:

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

Lai pārbaudītu, vai tie patiešām norāda uz vienu un to pašu objektu, mēs varam izmantot isoperatoru:

>>> x is z True

Protams, tas nozīmē, ka viņiem atmiņā ir viena adrese, ko mēs varam skaidri pārbaudīt, izmantojot id:

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

Un, protams, viņiem ir tāda pati vērtība, tāpēc mēs sagaidām x == zarī atgriešanos True:

>>> x == z True

Maināmi un nemaināmi objekti Python

Mēs esam teikuši, ka Python viss ir objekts, tomēr starp objektiem ir svarīga atšķirība. Daži objekti ir maināmi, bet daži ir nemainīgi .

Kā jau minēju iepriekš, šis fakts rada neskaidrības daudziem cilvēkiem, kuri ir jauni Python, tāpēc mēs pārliecināsimies, ka tas ir skaidrs.

Nemaināmi objekti Python

Dažiem Python veidiem, kad mēs esam izveidojuši šo tipu gadījumus, tie nekad nemainās. Tie nav maināmi .

Piemēram, intobjekti Python nav maināmi. Kas notiks, ja mēģināsim mainīt objekta vērtību int?

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

Nu, šķiet, ka mēs xveiksmīgi mainījāmies . Tieši šeit daudzi cilvēki apjūk. Kas tieši šeit notika zem pārsega? Izmantosim, idlai sīkāk izpētītu:

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

Tātad mēs varam redzēt, ka, piešķirot x = 24602, mēs nemainījām objekta vērtību, kas xiepriekš bija saistīta. Drīzāk mēs izveidojām jaunu objektu un piesaistījām tam nosaukumu x.

Tātad, pēc tam, kad, piešķirot 24601to x, izmantojot x = 24601, mums bija šādas valsts:

Pēc lietošanas x = 24602mēs izveidojām jaunu objektu un piesaistījām nosaukumu xšim jaunajam objektam. Otrs objekts ar vērtību 24601vairs nav sasniedzams ar x(vai šajā gadījumā ar citu nosaukumu):

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.

Pēc tam mēs uzzinājām, kāpēc vārdnīcas taustiņiem jābūt nemainīgiem Python.

Izpratne par to, kā Python "redz" objektus, ir atslēga, lai kļūtu par labāku Python programmētāju. Es ceru, ka šis ieraksts jums ir palīdzējis jūsu Python apgūšanā.

Omer Rosenbaum , Swimm tehnoloģiju vadītājs. Kiberapmācības eksperts un Checkpoint Security Academy dibinātājs. Datoru tīklu autors (ebreju valodā) . Apmeklējiet manu YouTube kanālu .