trey.io/news — a weekly Python tip
first doesn't always change second
>>> first = [2, 3]
>>> second = first
>>> first.append(5)
>>> second
[2, 3, 5]
>>> first = [2, 3]
>>> second = first
>>> first = [2, 3, 5]
>>> second
[2, 3]
>>> def square_all(numbers):
... for i, n in enumerate(numbers):
... numbers[i] = n ** 2
... return numbers
...
>>> numbers = [2, 1, 3, 4, 7]
>>> square_all(numbers)
[4, 1, 9, 16, 49]
>>> numbers
[4, 1, 9, 16, 49]
>>> matrix = [[0] * 3] * 3
>>> matrix
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> matrix[1][1] = 9
>>> matrix
[[0, 9, 0], [0, 9, 0], [0, 9, 0]]
>>> colors = ["purple", "blue", "green"]
>>> groups = dict.fromkeys(colors, [])
>>> groups
{'purple': [], 'blue': [], 'green': []}
>>> groups["purple"].append("duck")
>>> groups
{'purple': ['duck'], 'blue': ['duck'], 'green': ['duck']}
>>> class TodoList:
... def __init__(self, tasks=[]):
... self.tasks = tasks
...
>>> mon = TodoList()
>>> tue = TodoList()
>>> mon.tasks.append("Work on talk")
>>> tue.tasks
['Work on talk']
second = firstfor i, n in enumerate(numbers):
numbers[i] = n ** 2matrix = [[0] * 3] * 3groups = dict.fromkeys(colors, [])def __init__(self, tasks=[]):
self.tasks = tasks
>>> first = []
>>> second = first
>>> second.append(9)
>>> second
[9]
>>> first
[9]
>>> first = []
>>> second = first
>>> second.append(9)
>>> second
[9]
>>> first
[9]
>>> rows = [second]
>>>
| binding | 🪢 |
| reference | 📖 |
| pointer | 👉 |
>>> first = [2, 3]
>>> second = first
>>> first.append(5)
>>> second
[2, 3, 5]
>>> first = [2, 3]
>>> second = first
>>> first = [2, 3, 5]
>>> second
[2, 3]
>>> first = [2, 1, 3, 4]
>>> second = first
>>> first.append(7)
>>> second
[2, 1, 3, 4, 7]
>>> first = [100, 200, 300]
>>> second
[2, 1, 3, 4, 7]
>>>
Remember: variables point to objects
x”Changed the variable?
>>> x = [2, 3]
>>> x = [2, 3, 5]
Changed the object?
>>> x = [2, 3]
>>> x.append(5)
second = firstfor i, n in enumerate(numbers):
numbers[i] = n ** 2matrix = [[0] * 3] * 3groups = dict.fromkeys(colors, [])def __init__(self, tasks=[]):
self.tasks = tasks
>>> first == second # Equality
True
>>> first is second # Identity
True
Identity: the exact same object
Equality: an equivalent object
>>> first == second # Are these objects equal to the other?
True
>>> first is second # Do these variables point to the same object?
True
value is None
value == another_value
>>> e = 2.7
>>> from math import e
>>> for e in range(3):
... print(e)
...
0
1
2
>>> def e(): return 2.7
...
>>> class e: pass
...
>>> e
<class '__main__.e'>
def square_all(numbers):
for i, n in enumerate(numbers):
numbers[i] = n ** 2
return numbers
>>> numbers = [2, 1, 3, 4, 7]
>>> square_all(numbers)
[4, 1, 9, 16, 49]
>>> numbers
[4, 1, 9, 16, 49]
def square_all(numbers):
for i, n in enumerate(numbers):
numbers[i] = n ** 2 # DON'T DO THIS
return numbers
def square_all(numbers):
squares = []
for n in numbers:
squares.append(n ** 2)
return squares
def square_all(numbers):
return [
n ** 2
for n in numbers
]
def square_all(numbers):
for i, n in enumerate(numbers):
numbers[i] = n ** 2
return numbers
>>> some_list[0] = 8
>>> some_object.attribute = 4
second = firstfor i, n in enumerate(numbers):
numbers[i] = n ** 2matrix = [[0] * 3] * 3groups = dict.fromkeys(colors, [])def __init__(self, tasks=[]):
self.tasks = tasks*for some definitions of “data”
>>> first = []
>>> second = first
>>> second.append(9)
>>> second
[9]
>>> first
[9]
>>> rows = [second]
>>>
>>>
>>> first = []
>>> second = first
>>> second.append(9)
>>> second
[9]
>>> first
[9]
>>> rows = [second]
>>>
x in y
>>> matrix = [[0] * 3] * 3
>>> matrix
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> matrix[1][1] = 9
>>> matrix
[[0, 9, 0], [0, 9, 0], [0, 9, 0]]
>>> matrix = [[0] * 3] * 3
>>> matrix
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> matrix[1][1] = 9
>>> matrix
[[0, 9, 0], [0, 9, 0], [0, 9, 0]]
>>> matrix = [[0] * 3 for _ in range(3)]
>>> matrix[1][1] = 9
>>> matrix
[[0, 0, 0], [0, 9, 0], [0, 0, 0]]
second = firstfor i, n in enumerate(numbers):
numbers[i] = n ** 2matrix = [[0] * 3] * 3groups = dict.fromkeys(colors, [])def __init__(self, tasks=[]):
self.tasks = tasks
>>> colors = ["purple", "blue", "green"]
>>> groups = dict.fromkeys(colors, [])
>>> groups["purple"].append("duck")
>>> groups
{'purple': ['duck'], 'blue': ['duck'], 'green': ['duck']}
>>> colors = ["purple", "blue", "green"]
>>> groups = {color: [] for color in colors}
>>> groups["purple"].append("duck")
>>> groups
{'purple': ['duck'], 'blue': [], 'green': []}
second = firstfor i, n in enumerate(numbers):
numbers[i] = n ** 2matrix = [[0] * 3] * 3groups = dict.fromkeys(colors, [])def __init__(self, tasks=[]):
self.tasks = tasks
>>> class TodoList:
... def __init__(self, tasks=[]):
... self.tasks = tasks
...
>>> mon = TodoList()
>>> tue = TodoList()
>>> mon.tasks.append("Work on talk")
>>> tue.tasks
['Work on talk']
>>> TodoList.__init__.__defaults__[0]
['Work on talk']
>>> class TodoList:
... def __init__(self, tasks=[]):
... self.tasks = list(tasks)
...
>>> mon = TodoList()
>>> tue = TodoList()
>>> mon.tasks.append("Work on talk")
>>> tue.tasks
[]
>>> class TodoList:
... def __init__(self, tasks=[]):
... self.tasks = list(tasks)
...
>>> default_todos = ["Reflect on last week"]
>>> mon = TodoList(default_todos)
>>> tue = TodoList(default_todos)
>>> mon.tasks.append("Work on talk")
>>> mon.tasks
['Reflect on last week', 'Work on talk']
>>> tue.tasks
['Reflect on last week']
>>> wed = TodoList({"Here is", "a set", "of tasks"})
second = firstfor i, n in enumerate(numbers):
numbers[i] = n ** 2matrix = [[0] * 3] * 3groups = dict.fromkeys(colors, [])def __init__(self, tasks=[]):
self.tasks = taskssecond = first is a problem for mutable objectslist(...), etc.dict.fromkeys with a mutable default value will cause problemsNames, Objects, and Plummeting From The Cliff - Brandon Rhodes
Facts and Myths about Names and Values - Ned Batchelder
Would every assignment statement make a copy?
Would storing a reference to an object ever be possible?
"reference assignments" and "copying assignments" 😬
Trey Hunner
Python Team Trainer
[email protected]
© 2024 Akiyoshi Kitaoka, used with permission
#7c7c7c
"All models are wrong,
but some models are useful."— George E. P. Box
+=, -=, *=, etc.
Are these assignments?
Are these mutations?
>>> a = [2, 1, 3]
>>> b = a
>>> b += [4, 7, 11]
>>> b
[2, 1, 3, 4, 7, 11]
>>> a
[2, 1, 3, 4, 7, 11]
>>> name = "North Bay Python"
>>> name += " 2025" # name = name + "2025"
>>> name
'North Bay Python 2025'
* For some definitions of "mutate"
>>> result = (True, [2, 1, 3])
>>> result[1].append(4)
>>> result
(True, [2, 1, 3, 4])
>>> result = (True, [2, 1, 3])
>>> result2 = (True, [2, 1, 3])
>>> result == result2
True
>>> result[1].append(4)
>>> result
(True, [2, 1, 3, 4])
>>> result == result2
False
>>> result = (True, [2, 1, 3, 4])
>>> result[1] += [7, 11, 18]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
result[1] += [7, 11, 18]
~~~~~~^^^
TypeError: 'tuple' object does not support item assignment
>>> result
(True, [2, 1, 3, 4, 7, 11, 18])
>>> first = []
>>> second = first
>>> second.append(9)
>>> second
[9]
>>> first
[9]
>>>
>>> first = []
>>> second = first
>>> second.append(9)
>>> second
[9]
>>> first
[9]
>>> rows = [second]
>>> lists = rows