Recently, I occasionally read 《Fluent Python》, When you come across something interesting, write it down . The following is in PyCon2013 A question about tuple Of Augmented Assignment That is, the problem of incremental assignment . And based on this problem , It also extends 3 Variant questions .
problem
First, let's look at the first question , Such as the following code snippet :
>>> t = (1,2, [30,40])
>>> t[2] += [50,60]
What will happen ? Four options are given :
1. `t` become `[1,2, [30,40,50,60]`
2. `TypeError is raised with the message 'tuple' object does not support item assignment`
3. Neither 1 nor 2
4. Both 1 and 2
As previously understood , tuple The elements inside cannot be modified , So I will choose 2.
If so , This note is not necessary ,《Fluent Python》 So I won't take out a section .
The right answer is 4 :
>>> t = (1,2,[30,40])
>>> t[2] += [50,60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])
The problem is coming. , Why do all the anomalies come out ,t Still changed ?
Look at the second case , A little change , take += Turn into = :
>>> t = (1,2, [30,40])
>>> t[2] = [50,60]
It turns out to be dark brown :
>>> t = (1,2, [30,40])
>>> t[2] = [50,60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40])
Look at the third case , Only += Replace with extend perhaps append :
>>> t = (1, 2, [30,40])
>>> t[2].extend([50,60])
>>> t
(1, 2, [30, 40, 50, 60])
>>> t[2].append(70)
>>> t
(1, 2, [30, 40, 50, 60, 70])
It's normal again , No exception was thrown ?
Finally, the fourth case , In the form of variables :
>>> a = [30,40]
>>> t = (1, 2, a)
>>> a+=[50,60]
>>> a
[30, 40, 50, 60]
>>> t
(1, 2, [30, 40, 50, 60])
>>> t[2] += [70,80]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60, 70, 80])
Another situation , Let's explore the reasons .
reason
First, we need to review += This operator , Such as a+=b:
The following code snippet , You can see it :
>>> a = [1,2,3]
>>> id(a)
53430752
>>> a+=[4,5]
>>> a
[1, 2, 3, 4, 5]
>>> id(a)
53430752 # The address hasn't changed
>>> b = (1,2,3)
>>> id(b)
49134888
>>> b += (4,5)
>>> b
(1, 2, 3, 4, 5)
>>> id(b)
48560912 # The address has changed
In addition, it should be noted that , python Medium tuple As immutable objects , That is, the elements we usually say cannot be changed , In fact, from the error message TypeError: 'tuple' object does not support item assignment Look at , More precisely, the element does not support assignment =(assignment).
Let's first look at the simplest second case , Its result is in line with our expectations , because = Produced assign The operation of .( From an example to python The namespace of Assignment operations are indicated in = Is to create a new variable ), therefore s[2]=[50,60] Will throw an exception .
Look at the third case , contain extend/append Of , result tuple The list value in has changed , But no exception was thrown . This is also relatively easy to understand . Because we know tuple What is stored in is actually the address corresponding to the element (id), So if there is no assignment and tuple Of elements in id unchanged , that will do , and list.extend/append Just changed the elements of the list , And the list itself id There is no change , Take a look at the following example :
>>> a=(1,2,[30,40])
>>> id(a[2])
140628739513736
>>> a[2].extend([50,60])
>>> a
(1, 2, [30, 40, 50, 60])
>>> id(a[2])
140628739513736
At present, the second and third problems have been solved , Let's sort it out first , Actually, there are two points :
Now let's look at the first question : t[2] += [50,60] According to the above conclusion , You shouldn't throw exceptions , Because in our opinion += For mutable objects t[2] Come on , Belong to in-place operation , That is, you can directly modify your own content , id It doesn't change , To confirm the id There is no change :
>>> a=(1,2,[30,40])
>>> id(a[2])
140628739587392
>>> a[2]+=[50,60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a
(1, 2, [30, 40, 50, 60])
>>> id(a[2]) # ID Nothing has changed
140628739587392
With the third question, just from t[2].extend Changed to t[2]+=, Throw an exception , So the problem should be += Yes . The following is used dis The module looks at the steps that both of them perform , Execute... On the following code block dis:
t = (1,2, [30,40])
t[2] += [50,60]
t[2].extend([70, 80])
perform python -m dis test.py, give the result as follows , Only the... Is reserved below 2,3 Line code execution process , And notes on key steps are as follows :
2 21 LOAD_NAME 0 (t)
24 LOAD_CONST 1 (2)
27 DUP_TOPX 2
30 BINARY_SUBSCR
31 LOAD_CONST 4 (50)
34 LOAD_CONST 5 (60)
37 BUILD_LIST 2
40 INPLACE_ADD
41 ROT_THREE
42 STORE_SUBSCR
3 43 LOAD_NAME 0 (t)
46 LOAD_CONST 1 (2)
49 BINARY_SUBSCR
50 LOAD_ATTR 1 (extend)
53 LOAD_CONST 6 (70)
56 LOAD_CONST 7 (80)
59 BUILD_LIST 2
62 CALL_FUNCTION 1
65 POP_TOP
66 LOAD_CONST 8 (None)
69 RETURN_VALUE
Explain the key statements :
Look again extend The process of , The front is the same , Only this line :
Now it is becoming clear , let me put it another way ,+= It's not an atomic operation , It is equivalent to the following two steps :
t[2].extend([50,60])
t[2] = t[2]
The first step can be performed correctly , But the second step is =, It's bound to throw exceptions . This can also explain the use of += When , why t[2] Of id Obviously there is no change , But it still throws an exception .
Now let's sum it up in one sentence :
tuple Element in does not support assign operation , But for elements that are mutable objects, such as lists , Dictionary, etc , In the absence of assign On the basis of operation , For example, some in-place operation , The content can be modified
You can use the fourth question to simply verify , Use a pointer to [30,40] The name of a As the value of the element , Then on a do in-place Modification of , There is no reference to tuple Of assign operation , That must be normal .
The above is all the content shared this time , Want to know more python Welcome to official account :Python Programming learning circle , send out “J” Free access to , Daily dry goods sharing