Python subtleties
A collection of subtle (or not so subtle) mistakes I made and puzzles I’ve come across.
| |
Changing a mutable element of an immutable sequence
The puzzle is from page 40 in Fluent Python.
| |
TypeError: 'tuple' object does not support item assignment
| |
'tuple'
| |
(1, 2, [3, 4, 5, 6])
What’s going on here? As part of the assignment, Python does the following:
Performs augmented addition on the value of
t[2], which works because that value is the list[3, 4], which is mutable.Then it tries to assign the result from 1 to
t[2], which doesn’t work, becausetis immutable.But because the 2nd element in
tis not the list itself but a reference to it, and because the list was changed in step 1, the value oft[2]has changed, too.
A great way to visualise the process is to see what happens under the hood using the amazing Python Tutor.
NANs are True
I have a dataframe with some data:
| |
| data | |
|---|---|
| 0 | a |
| 1 | b |
| 2 | c |
| 3 | d |
| 4 | e |
I can shift the data column:
| |
0 NaN
1 a
2 b
3 c
4 d
Name: data, dtype: object
I want to add a check column that tells me where the shift is missing:
| |
| data | check | |
|---|---|---|
| 0 | a | ok |
| 1 | b | ok |
| 2 | c | ok |
| 3 | d | ok |
| 4 | e | ok |
That’s not what I wanted. The reason it happens is that missing values that aren’t None evaluate to True (follows from the docs). One way to see this:
| |
[nan, 'hello', True]
Hence, to get the check I wanted I should do this:
| |
| data | check | correct_check | |
|---|---|---|---|
| 0 | a | ok | missing |
| 1 | b | ok | ok |
| 2 | c | ok | ok |
| 3 | d | ok | ok |
| 4 | e | ok | ok |
Truthy vs True
As follows clearly from the docs, True is one of many values that evaluate to True. This seems clear enough. Yet I just caught myself getting confused by the following:
I have a list of values that I want to filter for Truthy elements – elements that evaluate to True:
| |
[nan, 'hello', True]
This works as intended. For a moment, however, I got confused by the following:
| |
[True]
I expected it to yield the same result as the above. But it doesn’t becuase it only returns valus that actually are True, as in having the same object ID as the value True (this Stack Overflow answer makes the point nicely). We can see this below:
| |
[4599359344, 4859333552, 4556488160, 4556589160]
| |
4556488160