|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "2462a390-11a0-4d96-be42-a215460ee554", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# Requirements" |
| 9 | + ] |
| 10 | + }, |
| 11 | + { |
| 12 | + "cell_type": "code", |
| 13 | + "execution_count": 1, |
| 14 | + "id": "4012d44e-1e7f-488d-bb19-d40466a0b800", |
| 15 | + "metadata": {}, |
| 16 | + "outputs": [], |
| 17 | + "source": [ |
| 18 | + "from collections import defaultdict\n", |
| 19 | + "from dataclasses import dataclass" |
| 20 | + ] |
| 21 | + }, |
| 22 | + { |
| 23 | + "cell_type": "markdown", |
| 24 | + "id": "62c1100f-d14c-4773-a87d-9b7935d55dcd", |
| 25 | + "metadata": {}, |
| 26 | + "source": [ |
| 27 | + "# defaultdict" |
| 28 | + ] |
| 29 | + }, |
| 30 | + { |
| 31 | + "cell_type": "markdown", |
| 32 | + "id": "771384fa-293a-4f00-94f9-0c5d28f19ed5", |
| 33 | + "metadata": {}, |
| 34 | + "source": [ |
| 35 | + "The `defaultdict` class is quite convenient since you don't have to test whether a key is already in a dictionary. If it is not, a factory is used to create an initial entry." |
| 36 | + ] |
| 37 | + }, |
| 38 | + { |
| 39 | + "cell_type": "markdown", |
| 40 | + "id": "f3951a33-b671-4603-8349-61c1641ae405", |
| 41 | + "metadata": {}, |
| 42 | + "source": [ |
| 43 | + "## Simple example" |
| 44 | + ] |
| 45 | + }, |
| 46 | + { |
| 47 | + "cell_type": "markdown", |
| 48 | + "id": "a2630300-45fd-4d51-8a05-a05bad9ee9d6", |
| 49 | + "metadata": {}, |
| 50 | + "source": [ |
| 51 | + "Consider a dictionary that has lists as values. If a key is not in the dictionary, it should be initialized with an empty list. The factory function for an empty list is the `list` function." |
| 52 | + ] |
| 53 | + }, |
| 54 | + { |
| 55 | + "cell_type": "code", |
| 56 | + "execution_count": 2, |
| 57 | + "id": "67799112-3eb0-4410-b260-5c4646adffa6", |
| 58 | + "metadata": { |
| 59 | + "tags": [] |
| 60 | + }, |
| 61 | + "outputs": [], |
| 62 | + "source": [ |
| 63 | + "multiples = defaultdict(list)" |
| 64 | + ] |
| 65 | + }, |
| 66 | + { |
| 67 | + "cell_type": "markdown", |
| 68 | + "id": "556ecf15-3003-49f8-aa9b-e9f3998f2855", |
| 69 | + "metadata": {}, |
| 70 | + "source": [ |
| 71 | + "Now we can add data to the dictionary, for each integer between 0 and 20, we check whether the number is divisible by 2, 3, 4, or 5, and append it to the list that is the value for the divisor (which is the key)." |
| 72 | + ] |
| 73 | + }, |
| 74 | + { |
| 75 | + "cell_type": "code", |
| 76 | + "execution_count": 3, |
| 77 | + "id": "34147d51-a265-46b8-9e22-10b81460c006", |
| 78 | + "metadata": {}, |
| 79 | + "outputs": [], |
| 80 | + "source": [ |
| 81 | + "for number in range(20):\n", |
| 82 | + " for divisor in range(2, 6):\n", |
| 83 | + " if number % divisor == 0:\n", |
| 84 | + " multiples[divisor].append(number)" |
| 85 | + ] |
| 86 | + }, |
| 87 | + { |
| 88 | + "cell_type": "code", |
| 89 | + "execution_count": 4, |
| 90 | + "id": "d533abb9-7fcc-4ddf-895b-a13a71af138a", |
| 91 | + "metadata": {}, |
| 92 | + "outputs": [ |
| 93 | + { |
| 94 | + "data": { |
| 95 | + "text/plain": [ |
| 96 | + "defaultdict(list,\n", |
| 97 | + " {2: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18],\n", |
| 98 | + " 3: [0, 3, 6, 9, 12, 15, 18],\n", |
| 99 | + " 4: [0, 4, 8, 12, 16],\n", |
| 100 | + " 5: [0, 5, 10, 15]})" |
| 101 | + ] |
| 102 | + }, |
| 103 | + "execution_count": 4, |
| 104 | + "metadata": {}, |
| 105 | + "output_type": "execute_result" |
| 106 | + } |
| 107 | + ], |
| 108 | + "source": [ |
| 109 | + "multiples" |
| 110 | + ] |
| 111 | + }, |
| 112 | + { |
| 113 | + "cell_type": "markdown", |
| 114 | + "id": "4fb29e3d-4264-4030-b933-b101c115d923", |
| 115 | + "metadata": {}, |
| 116 | + "source": [ |
| 117 | + "## Arbitrary classes" |
| 118 | + ] |
| 119 | + }, |
| 120 | + { |
| 121 | + "cell_type": "markdown", |
| 122 | + "id": "667ee4ca-6b2f-4ec0-823e-beef80dbbe93", |
| 123 | + "metadata": {}, |
| 124 | + "source": [ |
| 125 | + "`defaultdict` also supports arbitrary objects as default values. Consider the following dataclass that represents a person." |
| 126 | + ] |
| 127 | + }, |
| 128 | + { |
| 129 | + "cell_type": "code", |
| 130 | + "execution_count": 5, |
| 131 | + "id": "0d049fe8-5b12-4c35-a730-1ddb47db55e8", |
| 132 | + "metadata": {}, |
| 133 | + "outputs": [], |
| 134 | + "source": [ |
| 135 | + "@dataclass\n", |
| 136 | + "class Person:\n", |
| 137 | + " first_name: str = None\n", |
| 138 | + " last_name: str = None\n", |
| 139 | + " age: int = None" |
| 140 | + ] |
| 141 | + }, |
| 142 | + { |
| 143 | + "cell_type": "markdown", |
| 144 | + "id": "928778d2-6fd8-4662-bb31-857e3a87f2c5", |
| 145 | + "metadata": {}, |
| 146 | + "source": [ |
| 147 | + "The constructor is the default factory in this case." |
| 148 | + ] |
| 149 | + }, |
| 150 | + { |
| 151 | + "cell_type": "code", |
| 152 | + "execution_count": 6, |
| 153 | + "id": "1eec5ce6-3d7e-4e64-abd1-86f5f92e1446", |
| 154 | + "metadata": {}, |
| 155 | + "outputs": [], |
| 156 | + "source": [ |
| 157 | + "people = defaultdict(Person)" |
| 158 | + ] |
| 159 | + }, |
| 160 | + { |
| 161 | + "cell_type": "markdown", |
| 162 | + "id": "aa0d20b2-ef70-487f-8637-cc6060355c1f", |
| 163 | + "metadata": {}, |
| 164 | + "source": [ |
| 165 | + "When a new person turns up, a default `Person` is constructed with `None` for each attribute, and one of the attributes, `first_name` is assigned to below." |
| 166 | + ] |
| 167 | + }, |
| 168 | + { |
| 169 | + "cell_type": "code", |
| 170 | + "execution_count": 7, |
| 171 | + "id": "6732bd91-c726-4603-b4c4-7c70fc5eae7d", |
| 172 | + "metadata": {}, |
| 173 | + "outputs": [], |
| 174 | + "source": [ |
| 175 | + "people['gjb'].first_name = 'Geert Jan'" |
| 176 | + ] |
| 177 | + }, |
| 178 | + { |
| 179 | + "cell_type": "markdown", |
| 180 | + "id": "63b5c683-0a51-45e1-9d65-c9527e75136d", |
| 181 | + "metadata": {}, |
| 182 | + "source": [ |
| 183 | + "The dictionary indeed contains a single entry, a `Person` with `first_name` initialized, and `liast_name` and `age` attributes still set to `None`." |
| 184 | + ] |
| 185 | + }, |
| 186 | + { |
| 187 | + "cell_type": "code", |
| 188 | + "execution_count": 8, |
| 189 | + "id": "c510d857-6796-48c4-a181-9ce58828cc2f", |
| 190 | + "metadata": {}, |
| 191 | + "outputs": [ |
| 192 | + { |
| 193 | + "data": { |
| 194 | + "text/plain": [ |
| 195 | + "defaultdict(__main__.Person,\n", |
| 196 | + " {'gjb': Person(first_name='Geert Jan', last_name=None, age=None)})" |
| 197 | + ] |
| 198 | + }, |
| 199 | + "execution_count": 8, |
| 200 | + "metadata": {}, |
| 201 | + "output_type": "execute_result" |
| 202 | + } |
| 203 | + ], |
| 204 | + "source": [ |
| 205 | + "people" |
| 206 | + ] |
| 207 | + } |
| 208 | + ], |
| 209 | + "metadata": { |
| 210 | + "kernelspec": { |
| 211 | + "display_name": "Python 3", |
| 212 | + "language": "python", |
| 213 | + "name": "python3" |
| 214 | + }, |
| 215 | + "language_info": { |
| 216 | + "codemirror_mode": { |
| 217 | + "name": "ipython", |
| 218 | + "version": 3 |
| 219 | + }, |
| 220 | + "file_extension": ".py", |
| 221 | + "mimetype": "text/x-python", |
| 222 | + "name": "python", |
| 223 | + "nbconvert_exporter": "python", |
| 224 | + "pygments_lexer": "ipython3", |
| 225 | + "version": "3.9.5" |
| 226 | + }, |
| 227 | + "toc-autonumbering": true |
| 228 | + }, |
| 229 | + "nbformat": 4, |
| 230 | + "nbformat_minor": 5 |
| 231 | +} |
0 commit comments