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
@@ -65,82 +64,17 @@ What does the error message say went wrong? Do you think this is a good message?
65
64
The error says we can't multiply sequences with a non-int of type float and points to the sub-expression `r * x`. However, the mistake is made at the call point by entering a `str` argument in the first place.
66
65
::::
67
66
68
-
How about the following code?
69
-
70
-
```python
71
-
defbinary_search(lst, value):
72
-
low =0
73
-
high =len(lst)-1
74
-
while low <= high:
75
-
mid = (low+high) /2
76
-
if lst[mid] > value:
77
-
high = mid-1
78
-
elif lst[mid] < value:
79
-
low = mid+1
80
-
else:
81
-
return mid
82
-
return-1
83
-
84
-
binary_search([3.4, 7.8, 9.1], 5.2)
85
-
```
86
-
87
-
Run a type-checker on the binary search example. What does it say?
88
-
89
-
:::: solution
90
-
We can't index `lst` with a floating point value. The mistake is at the division by 2, we should have used the `//` operator.
91
-
::::
92
-
93
-
Add type annotation to these codes:
67
+
Change the function signature to:
94
68
95
69
```python
96
70
deflogistic_map(r: float, x: float) -> float:
97
71
return r * x * (1- x)
98
72
```
99
73
100
-
Do we get nicer messages now? How about our binary search? We're not restricted to typing function arguments (although that's the most common use). By explicitly typing intermediate values, we may catch errors early.
101
-
102
-
```python
103
-
defbinary_search(lst: list, value) -> int:
104
-
low: int=0
105
-
high: int=len(lst)-1
106
-
while low <= high:
107
-
mid: int= (low+high) /2
108
-
if lst[mid] > value:
109
-
high = mid-1
110
-
elif lst[mid] < value:
111
-
low = mid+1
112
-
else:
113
-
return mid
114
-
return-1
115
-
```
116
-
117
-
Is the problem now identified with `mypy`? Note that we haven't typed `value` yet: we'll get to that later.
118
-
119
-
:::: solution
120
-
In the `logistic_map` example we find that type hinting the arguments helps us identify that the caller made a mistake.
121
-
Only by specifying that we expect `mid` to be an integer, is the true culprit revealed.
122
-
::::
123
-
74
+
Do you see any effect in on the erronous call in your editor?
124
75
:::
125
76
126
-
## Union types
127
-
128
-
Sometimes we don't know the exact type of a value, or we'd lik to specify that a function can handle multiple different types. This is where type unions come in. For example, in the binary search, it is nicer to return `None` when we don't find an item. We can use the `|` operator to create a **type union**.
129
-
130
-
```python
131
-
defbinary_search(lst: list, value) -> int|None:
132
-
low: int=0
133
-
high: int=len(lst)-1
134
-
while low <= high:
135
-
mid: int= (low+high) //2
136
-
if lst[mid] > value:
137
-
high = mid-1
138
-
elif lst[mid] < value:
139
-
low = mid+1
140
-
else:
141
-
return mid
142
-
returnNone
143
-
```
77
+
### Abstract types
144
78
145
79
We don't always care about the precise type of an object. For instance, if we just want to write a for loop over an iterable, and sometimes we want to express that `Any` object will do:
There are many abstract types available in `collections.abc`.
91
+
92
+
### Completion
93
+
94
+
Write a function that changes all commas to semi-colons. Start by entering the following:
95
+
96
+
```python
97
+
defsemicolonize(s: str) -> str:
98
+
return s
99
+
```
100
+
101
+
Type a `.` after the `s`. Can you see the completion?
102
+
156
103
## Data classes
157
104
158
105
::: info
159
106
### Data before classes
160
107
In many languages structures or records are considered more primitive than classes, not so in Python. We will learn more about classes and their place in software design in part 3. In this section we'll only consider data classes as a means of grouping data.
161
108
:::
162
109
163
-
Type annotations go really well together with data classes, a means of combining elements into a larger data structure.
110
+
Type annotations go really well together with data classes, a means of combining elements into a larger data structure. Python supports creating classes using type annotation like so:
Now you don't need to define an `__init__` method. There are nice packages that use this technique to allow automatic serialisation and deserialisation. Check out the [`msgspec` package](https://jcristharif.com/msgspec/index.html).
127
+
179
128
::: challenge
180
129
### Autocompletion
181
130
@@ -191,6 +140,19 @@ When you use type-annotation, you'll have better auto-completion.
191
140
::::
192
141
:::
193
142
143
+
::: challenge
144
+
### Serialization
145
+
146
+
Install `msgspec` and try writing and reading back an `Address` object to JSON. Can you think of the advantages of using this approach over Python native `json.dump`?
147
+
148
+
:::: solution
149
+
- less code
150
+
- automatic validation
151
+
- user friendly error reporting
152
+
- high performance
153
+
::::
154
+
:::
155
+
194
156
## Optional: Generics and protocols
195
157
196
158
How would we type a function that returns the first element in a list? Suppose that we know that the list contains integers. Then:
0 commit comments