You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Otherwise it would be impossible to decrypt messages properly. If both `'h'` and `'j'` got replaced with `'q'`
1049
1049
during encryption, there would be no way to know whether `'qpeef'` means `'hello'` or `'jello'`!
1050
1050
"""
1051
+
1052
+
1053
+
classCopyingDictionaries(Page):
1054
+
title="Copying Dictionaries"
1055
+
1056
+
classshared_references(VerbatimStep):
1057
+
"""
1058
+
Remember how assigning one list variable to another (`list2 = list1`) made both names point to the *same* list? Dictionaries work the same way because they are also *mutable* (can be changed).
1059
+
1060
+
Predict what the following code will print, then run it to see:
1061
+
1062
+
__copyable__
1063
+
__program_indented__
1064
+
"""
1065
+
defprogram(self):
1066
+
d1= {'a': 1, 'b': 2}
1067
+
d2=d1
1068
+
1069
+
print("d1 before:", d1)
1070
+
print("d2 before:", d2)
1071
+
print("Are they the same object?", d1isd2)
1072
+
1073
+
d2['c'] =3# Modify via d2
1074
+
1075
+
print("d1 after:", d1) # Is d1 affected?
1076
+
print("d2 after:", d2)
1077
+
1078
+
predicted_output_choices= [
1079
+
# Incorrect prediction (d1 unaffected)
1080
+
"""d1 before: {'a': 1, 'b': 2}
1081
+
d2 before: {'a': 1, 'b': 2}
1082
+
Are they the same object? True
1083
+
d1 after: {'a': 1, 'b': 2}
1084
+
d2 after: {'a': 1, 'b': 2, 'c': 3}""",
1085
+
1086
+
# Correct prediction
1087
+
"""d1 before: {'a': 1, 'b': 2}
1088
+
d2 before: {'a': 1, 'b': 2}
1089
+
Are they the same object? True
1090
+
d1 after: {'a': 1, 'b': 2, 'c': 3}
1091
+
d2 after: {'a': 1, 'b': 2, 'c': 3}""",
1092
+
1093
+
# Incorrect prediction (is False)
1094
+
"""d1 before: {'a': 1, 'b': 2}
1095
+
d2 before: {'a': 1, 'b': 2}
1096
+
Are they the same object? False
1097
+
d1 after: {'a': 1, 'b': 2}
1098
+
d2 after: {'a': 1, 'b': 2, 'c': 3}""",
1099
+
]
1100
+
1101
+
classmaking_copies(VerbatimStep):
1102
+
"""
1103
+
Because `d1` and `d2` referred to the exact same dictionary object (`d1 is d2` was `True`), changing it via `d2` also changed what `d1` saw.
1104
+
1105
+
To get a *separate* dictionary with the same contents, use the `.copy()` method.
1106
+
1107
+
Predict how using `.copy()` changes the outcome, then run this code:
1108
+
1109
+
__copyable__
1110
+
__program_indented__
1111
+
"""
1112
+
defprogram(self):
1113
+
d1= {'a': 1, 'b': 2}
1114
+
d2=d1.copy() # Create a separate copy
1115
+
1116
+
print("d1 before:", d1)
1117
+
print("d2 before:", d2)
1118
+
print("Are they the same object?", d1isd2)
1119
+
1120
+
d2['c'] =3# Modify the copy
1121
+
1122
+
print("d1 after:", d1) # Is d1 affected now?
1123
+
print("d2 after:", d2)
1124
+
1125
+
predicted_output_choices= [
1126
+
# Incorrect prediction (is True)
1127
+
"""d1 before: {'a': 1, 'b': 2}
1128
+
d2 before: {'a': 1, 'b': 2}
1129
+
Are they the same object? True
1130
+
d1 after: {'a': 1, 'b': 2, 'c': 3}
1131
+
d2 after: {'a': 1, 'b': 2, 'c': 3}""",
1132
+
1133
+
# Incorrect prediction (d1 affected)
1134
+
"""d1 before: {'a': 1, 'b': 2}
1135
+
d2 before: {'a': 1, 'b': 2}
1136
+
Are they the same object? False
1137
+
d1 after: {'a': 1, 'b': 2, 'c': 3}
1138
+
d2 after: {'a': 1, 'b': 2, 'c': 3}""",
1139
+
1140
+
# Correct prediction
1141
+
"""d1 before: {'a': 1, 'b': 2}
1142
+
d2 before: {'a': 1, 'b': 2}
1143
+
Are they the same object? False
1144
+
d1 after: {'a': 1, 'b': 2}
1145
+
d2 after: {'a': 1, 'b': 2, 'c': 3}""",
1146
+
]
1147
+
1148
+
classpositive_stock_exercise(ExerciseStep):
1149
+
"""
1150
+
Making an exact copy is useful, but often we want a *modified* copy. Let's practice creating a new dictionary based on an old one.
1151
+
1152
+
Write a function `positive_stock(stock)` that takes a dictionary `stock` (mapping item names to integer quantities) and returns a *new* dictionary containing only the items from the original `stock` where the quantity is strictly greater than 0. The original `stock` dictionary should not be changed.
# Generate a dictionary with some zero/negative and positive values
1203
+
stock= {}
1204
+
num_items=random.randint(3, 8)
1205
+
for_inrange(num_items):
1206
+
item=generate_string(random.randint(3, 6))
1207
+
# Ensure some variety in quantities
1208
+
ifrandom.random() <0.4:
1209
+
quantity=0
1210
+
elifrandom.random() <0.2:
1211
+
quantity=random.randint(-5, -1)
1212
+
else:
1213
+
quantity=random.randint(1, 20)
1214
+
stock[item] =quantity
1215
+
# Ensure at least one positive if dict not empty
1216
+
ifstockandall(q<=0forqinstock.values()):
1217
+
stock[generate_string(4)] =random.randint(1, 10)
1218
+
return {"stock": stock}
1219
+
1220
+
classadd_item_exercise(ExerciseStep):
1221
+
"""
1222
+
Let's practice combining copying and modifying. Imagine we want to represent adding one unit of an item to our stock count.
1223
+
1224
+
Write a function `add_item(item, quantities)` that takes an item name (`item`) and a dictionary `quantities`. You can assume the `item` *already exists* as a key in the `quantities` dictionary.
1225
+
1226
+
The function should return a *new* dictionary which is a copy of `quantities`, but with the value associated with `item` increased by 1. The original `quantities` dictionary should not be changed.
1227
+
1228
+
__copyable__
1229
+
def add_item(item, quantities):
1230
+
# Your code here
1231
+
...
1232
+
1233
+
stock = {'apple': 5, 'banana': 2}
1234
+
new_stock = add_item('apple', stock)
1235
+
assert_equal(stock, {'apple': 5, 'banana': 2}) # Original unchanged
1236
+
assert_equal(new_stock, {'apple': 6, 'banana': 2}) # Copy has incremented value
Well done! Notice that the line where you increment the value:
1277
+
1278
+
new_quantities[item] = new_quantities[item] + 1
1279
+
1280
+
can also be written more concisely using the `+=` operator, just like with numbers:
1281
+
1282
+
new_quantities[item] += 1
1283
+
1284
+
This does the same thing: it reads the current value, adds 1, and assigns the result back.
1285
+
"""
1286
+
1287
+
final_text="""
1288
+
Great! You now know why copying dictionaries is important (because they are mutable) and how to do it using `.copy()`. You've also practiced creating modified copies, which is a common and safe way to work with data without accidentally changing things elsewhere in your program.
1289
+
1290
+
Next, we'll see how to check if a key exists *before* trying to use it, to avoid errors.
0 commit comments