Skip to content

Commit 2cf3378

Browse files
authored
Merge pull request #8 from gjbex/development
Add metaclasses
2 parents c11df69 + 671bdb8 commit 2cf3378

39 files changed

+1520
-71
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,10 @@ For information on the training, see the website
2020
1. [Contributing](CONTRIBUTING.md): information on how to contribute to this
2121
repository.
2222
1. docs: directory containing the website for this repository.
23+
24+
## Contributors
25+
26+
* Geert Jan Bex ([[email protected]](mailto:[email protected])),
27+
Hasselt University/University of Leuven
28+
* Mustafa Dikmen, University of Leuven
29+
* correcting typos and pointing out various mistakes

environment.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ dependencies:
66
- jupyterlab
77
- flake8
88
- pytest
9-
- python=3.9
9+
- python=3.10
1010
- mypy
1111
- pylint
1212
- matplotlib

python_software_engineering.pptx

-19 Bytes
Binary file not shown.

source-code/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ was used to develop it.
2626
`pytest`.
2727
1. `oo_vs_functional.ipynb`: comparing object-oriented approach to
2828
functional approach, including coroutines.
29+
1. `metaclasses`: illustration of the use of metaclasses in Python.
30+
1. `data-structures`: illustration of Python and standard library data
31+
structures.

source-code/data-structures/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Data structures
2+
3+
Python as well as its standard library have many data structures that help you
4+
write elegant and efficient code. Here you will soe examples.
5+
6+
7+
## What is it?
8+
9+
1. `defaultdict.ipynb`: Jupyter notebook that illustrates the use of
10+
`collections.defaultdict` with a default factory for a Python `list` and
11+
a `dataclasss`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
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+
}

source-code/design-patters/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ Code to illustrate some design patterns in Python.
88
can be used to change the behaviour of objects.
99
1. `factory_design_pattern.ipynb`: notebook illustrating how a factory class
1010
can be used to conveniently construct many objects with the same properties.
11+
* `finite-state-parser`: illustration of object-oriented data
12+
representation and the state pattern.

source-code/functional-programming/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ Some examples of a functional programming style in Python.
44
## What is it?
55
1. `functional_programming_style.ipynb`: notebook explaining a functional
66
programming style in Python with examples.
7+
1. `sieve_of_eratosthenes.ipynb`: a lazy implementation of the sieve of
8+
Eratosthenes using generators.

0 commit comments

Comments
 (0)