Skip to content

Commit 3158989

Browse files
committed
Add section on hashing
1 parent 80de485 commit 3158989

File tree

1 file changed

+270
-0
lines changed

1 file changed

+270
-0
lines changed

source-code/object-orientation/attr_intro.ipynb

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,276 @@
11171117
"source": [
11181118
"alice1 == alice3"
11191119
]
1120+
},
1121+
{
1122+
"cell_type": "markdown",
1123+
"id": "748fa453-3827-4eb8-a012-f0d8d15aa183",
1124+
"metadata": {},
1125+
"source": [
1126+
"You can exclude attrubutes from being used to compare objects for equality by adding the argument `eq=False` to the `attr.ib` function call. Similarly, you can exclude an attribute from order comparisons by setting `order` to `False`."
1127+
]
1128+
},
1129+
{
1130+
"cell_type": "markdown",
1131+
"id": "6e3b0777-f567-47cb-8823-1e462d370be5",
1132+
"metadata": {},
1133+
"source": [
1134+
"## Hashing"
1135+
]
1136+
},
1137+
{
1138+
"cell_type": "markdown",
1139+
"id": "03d02551-2b9f-4d28-86a6-64c7550b847b",
1140+
"metadata": {},
1141+
"source": [
1142+
"Mutable objects are not hashable, which means they can not be stored in sets, or used as keys in dictionaries."
1143+
]
1144+
},
1145+
{
1146+
"cell_type": "code",
1147+
"execution_count": 32,
1148+
"id": "6d576453-68e9-4bae-b8b8-378565960668",
1149+
"metadata": {},
1150+
"outputs": [
1151+
{
1152+
"name": "stdout",
1153+
"output_type": "stream",
1154+
"text": [
1155+
"unhashable type: 'Person'\n"
1156+
]
1157+
}
1158+
],
1159+
"source": [
1160+
"try:\n",
1161+
" people = {\n",
1162+
" Person(firstname='Alice', lastname='Zosimo', age=43),\n",
1163+
" Person(firstname='Aaron', lastname='Leibovitch', age=31),\n",
1164+
" }\n",
1165+
"except Exception as error:\n",
1166+
" print(error)"
1167+
]
1168+
},
1169+
{
1170+
"cell_type": "markdown",
1171+
"id": "46e907e6-3278-4cec-b595-fc15a79a18ad",
1172+
"metadata": {},
1173+
"source": [
1174+
"One options is to make the objects unmutable."
1175+
]
1176+
},
1177+
{
1178+
"cell_type": "code",
1179+
"execution_count": 33,
1180+
"id": "8c34e55f-f798-417c-808a-a70cab41d9b0",
1181+
"metadata": {},
1182+
"outputs": [],
1183+
"source": [
1184+
"@attr.s(frozen=True)\n",
1185+
"class Person:\n",
1186+
" lastname: str = attr.ib()\n",
1187+
" firstname: str = attr.ib()\n",
1188+
" age: int = attr.ib()\n",
1189+
" \n",
1190+
" @age.validator\n",
1191+
" def age_validator(self, attribute, value):\n",
1192+
" if value < 0 or value >= 130:\n",
1193+
" raise ValueError(f'age should be between 0 and 130')"
1194+
]
1195+
},
1196+
{
1197+
"cell_type": "code",
1198+
"execution_count": 53,
1199+
"id": "922f49dd-c4cf-4554-9376-5e0185158f31",
1200+
"metadata": {},
1201+
"outputs": [
1202+
{
1203+
"data": {
1204+
"text/plain": [
1205+
"{Person(lastname='Leibovitch', firstname='Aaron', age=31),\n",
1206+
" Person(lastname='Zosimo', firstname='Alice', age=43)}"
1207+
]
1208+
},
1209+
"execution_count": 53,
1210+
"metadata": {},
1211+
"output_type": "execute_result"
1212+
}
1213+
],
1214+
"source": [
1215+
"people = {\n",
1216+
" Person(firstname='Alice', lastname='Zosimo', age=43),\n",
1217+
" Person(firstname='Aaron', lastname='Leibovitch', age=31),\n",
1218+
"}\n",
1219+
"people"
1220+
]
1221+
},
1222+
{
1223+
"cell_type": "markdown",
1224+
"id": "0133fe30-3973-4398-8c8d-e62bd504c519",
1225+
"metadata": {},
1226+
"source": [
1227+
"However, this implies you can not modify the objects."
1228+
]
1229+
},
1230+
{
1231+
"cell_type": "code",
1232+
"execution_count": 55,
1233+
"id": "37c2e8a4-2977-42b9-9529-30dfe1089f44",
1234+
"metadata": {},
1235+
"outputs": [
1236+
{
1237+
"name": "stdout",
1238+
"output_type": "stream",
1239+
"text": [
1240+
"Person(lastname='Leibovitch', firstname='Aaron', age=31)\n",
1241+
"the objects is frozen\n",
1242+
"Person(lastname='Leibovitch', firstname='Aaron', age=31)\n"
1243+
]
1244+
}
1245+
],
1246+
"source": [
1247+
"person = people.pop()\n",
1248+
"print(person)\n",
1249+
"try:\n",
1250+
" person.age = 12\n",
1251+
"except AttributeError:\n",
1252+
" print('the objects is frozen')\n",
1253+
"print(person)"
1254+
]
1255+
},
1256+
{
1257+
"cell_type": "markdown",
1258+
"id": "5554878d-ad20-4317-b58a-54c3c8958e2b",
1259+
"metadata": {},
1260+
"source": [
1261+
"This is of course fine if you do not need mutable ojbects. The alternative is to hash based on object identity."
1262+
]
1263+
},
1264+
{
1265+
"cell_type": "code",
1266+
"execution_count": 56,
1267+
"id": "f6269b27-ff89-40e8-bb85-5602cb0d6c72",
1268+
"metadata": {},
1269+
"outputs": [],
1270+
"source": [
1271+
"@attr.s(eq=False)\n",
1272+
"class Person:\n",
1273+
" lastname: str = attr.ib()\n",
1274+
" firstname: str = attr.ib()\n",
1275+
" age: int = attr.ib()\n",
1276+
" \n",
1277+
" @age.validator\n",
1278+
" def age_validator(self, attribute, value):\n",
1279+
" if value < 0 or value >= 130:\n",
1280+
" raise ValueError(f'age should be between 0 and 130')"
1281+
]
1282+
},
1283+
{
1284+
"cell_type": "markdown",
1285+
"id": "1e82961c-5ffb-43b4-b7e3-8e607beed8c7",
1286+
"metadata": {},
1287+
"source": [
1288+
"However, this implies that objects will be distinct, regardless of the values of their attributes."
1289+
]
1290+
},
1291+
{
1292+
"cell_type": "code",
1293+
"execution_count": 58,
1294+
"id": "4ca729cc-2ce4-470e-befd-bab544ae1f3c",
1295+
"metadata": {},
1296+
"outputs": [
1297+
{
1298+
"data": {
1299+
"text/plain": [
1300+
"{Person(lastname='Leibovitch', firstname='Aaron', age=31),\n",
1301+
" Person(lastname='Leibovitch', firstname='Robert', age=49),\n",
1302+
" Person(lastname='Zosimo', firstname='Alice', age=43),\n",
1303+
" Person(lastname='Zosimo', firstname='Alice', age=43)}"
1304+
]
1305+
},
1306+
"execution_count": 58,
1307+
"metadata": {},
1308+
"output_type": "execute_result"
1309+
}
1310+
],
1311+
"source": [
1312+
"people = {\n",
1313+
" Person(firstname='Alice', lastname='Zosimo', age=43),\n",
1314+
" Person(firstname='Aaron', lastname='Leibovitch', age=31),\n",
1315+
" Person(firstname='Robert', lastname='Leibovitch', age=49),\n",
1316+
" Person(firstname='Alice', lastname='Zosimo', age=43),\n",
1317+
"}\n",
1318+
"people"
1319+
]
1320+
},
1321+
{
1322+
"cell_type": "code",
1323+
"execution_count": 59,
1324+
"id": "086f2880-5772-4cd1-ba58-44576678d0b6",
1325+
"metadata": {},
1326+
"outputs": [],
1327+
"source": [
1328+
"alice1 = Person(firstname='Alice', lastname='Zosimo', age=43)\n",
1329+
"alice2 = Person(firstname='Alice', lastname='Zosimo', age=43)\n",
1330+
"alice3 = Person(firstname='alice', lastname='zosimo', age=43)"
1331+
]
1332+
},
1333+
{
1334+
"cell_type": "markdown",
1335+
"id": "ca98822f-691f-40a3-bb67-bbf989d87698",
1336+
"metadata": {},
1337+
"source": [
1338+
"`alice1` has the same attributes as `alice2`, but they are distinct objects nevertheless."
1339+
]
1340+
},
1341+
{
1342+
"cell_type": "code",
1343+
"execution_count": 60,
1344+
"id": "d5cb600d-f440-4919-9397-1e9b75af0d0f",
1345+
"metadata": {},
1346+
"outputs": [
1347+
{
1348+
"data": {
1349+
"text/plain": [
1350+
"False"
1351+
]
1352+
},
1353+
"execution_count": 60,
1354+
"metadata": {},
1355+
"output_type": "execute_result"
1356+
}
1357+
],
1358+
"source": [
1359+
"alice1 == alice2"
1360+
]
1361+
},
1362+
{
1363+
"cell_type": "code",
1364+
"execution_count": 61,
1365+
"id": "07a70926-54a2-425f-acb2-6aa22260f7c3",
1366+
"metadata": {},
1367+
"outputs": [
1368+
{
1369+
"data": {
1370+
"text/plain": [
1371+
"False"
1372+
]
1373+
},
1374+
"execution_count": 61,
1375+
"metadata": {},
1376+
"output_type": "execute_result"
1377+
}
1378+
],
1379+
"source": [
1380+
"alice1 is alice2"
1381+
]
1382+
},
1383+
{
1384+
"cell_type": "markdown",
1385+
"id": "1600b5e8-e10c-4eff-a369-87bc3920a8d3",
1386+
"metadata": {},
1387+
"source": [
1388+
"Of course, you can still impliment your own hash method and comparison methods if required."
1389+
]
11201390
}
11211391
],
11221392
"metadata": {

0 commit comments

Comments
 (0)