|
| 1 | +# Python 3.11 Demos |
| 2 | + |
| 3 | +This repository holds example code that demos some of the new features in Python 3.11. |
| 4 | + |
| 5 | +## Introduction |
| 6 | + |
| 7 | +You need Python 3.11 installed to run these examples. See the following tutorial instructions: |
| 8 | + |
| 9 | +- [How Can You Install a Pre-Release Version of Python](https://realpython.com/python-pre-release/) |
| 10 | + |
| 11 | +You can learn more about Python 3.11's new features in the following Real Python tutorials: |
| 12 | + |
| 13 | +- [Python 3.11 Preview: Even Better Error Messages](https://realpython.com/python311-error-messages/) |
| 14 | +- [Python 3.11 Preview: Task and Exception Groups](https://realpython.com/python311-exception-groups/) |
| 15 | +- [Python 3.11 Preview: TOML and `tomllib`](https://realpython.com/python311-tomllib/) |
| 16 | + |
| 17 | +You'll find examples from all these tutorials in this repository. |
| 18 | + |
| 19 | +## Dependencies |
| 20 | + |
| 21 | +Install necessary dependencies for the examples: |
| 22 | + |
| 23 | +```console |
| 24 | +$ python -m pip install colorama parse |
| 25 | +``` |
| 26 | + |
| 27 | +## Examples |
| 28 | + |
| 29 | +This section only contains brief instructions on how you can run the examples. See the tutorials for technical details. |
| 30 | + |
| 31 | +### Improved Error Messages |
| 32 | + |
| 33 | +Load [`scientists.py`](scientists.py) into your interactive REPL: |
| 34 | + |
| 35 | +```console |
| 36 | +$ python -i scientists.py |
| 37 | +``` |
| 38 | +You can then experiment with `dict_to_person()` and `convert_pair()`: |
| 39 | + |
| 40 | +```pycon |
| 41 | +>>> dict_to_person(scientists[1]) |
| 42 | +Traceback (most recent call last): |
| 43 | + ... |
| 44 | + File "/home/realpython/scientists.py", line 37, in dict_to_person |
| 45 | + name=f"{info['name']['first']} {info['name']['last']}", |
| 46 | + ~~~~~~~~~~~~^^^^^^^^ |
| 47 | +KeyError: 'last' |
| 48 | + |
| 49 | +>>> convert_pair(scientists[0], scientists[2]) |
| 50 | +Traceback (most recent call last): |
| 51 | + ... |
| 52 | + File "/home/realpython/scientists.py", line 44, in convert_pair |
| 53 | + return dict_to_person(first), dict_to_person(second) |
| 54 | + ^^^^^^^^^^^^^^^^^^^^^^ |
| 55 | + File "/home/realpython/scientists.py", line 38, in dict_to_person |
| 56 | + life_span=(info["birth"]["year"], info["death"]["year"]), |
| 57 | + ~~~~~~~~~~~~~^^^^^^^^ |
| 58 | +TypeError: 'NoneType' object is not subscriptable |
| 59 | +``` |
| 60 | + |
| 61 | +See [Even Better Error Messages in Python 3.11](https://realpython.com/python311-error-messages/#even-better-error-messages-in-python-311) and [PEP 657](https://peps.python.org/pep-0657/). |
| 62 | + |
| 63 | +### Exception Groups |
| 64 | + |
| 65 | +Use `ExceptionGroup` and `except*` to handle several errors at once: |
| 66 | + |
| 67 | +```pycon |
| 68 | +>>> try: |
| 69 | +... raise ExceptionGroup( |
| 70 | +... "group", [TypeError("str"), ValueError(654), TypeError("int")] |
| 71 | +... ) |
| 72 | +... except* ValueError as eg: |
| 73 | +... print(f"Handling ValueErrors: {eg.exceptions}") |
| 74 | +... |
| 75 | +Handling ValueErrors: (ValueError(654),) |
| 76 | + + Exception Group Traceback (most recent call last): |
| 77 | + | ... |
| 78 | + | ExceptionGroup: group (2 sub-exceptions) |
| 79 | + +-+---------------- 1 ---------------- |
| 80 | + | TypeError: str |
| 81 | + +---------------- 2 ---------------- |
| 82 | + | TypeError: int |
| 83 | + +------------------------------------ |
| 84 | +``` |
| 85 | + |
| 86 | +See [Exception Groups and `except*` in Python 3.11](https://realpython.com/python311-exception-groups/#exception-groups-and-except-in-python-311) and [PEP 654](https://peps.python.org/pep-0654/). |
| 87 | + |
| 88 | +### Task Groups |
| 89 | + |
| 90 | +Run [`count.py`](count.py), [`count_gather.py`](count_gather.py), and [`count_taskgroup.py`](count_taskgroup.py) and compare their behaviors. For example: |
| 91 | + |
| 92 | +```console |
| 93 | +$ python count_taskgroup.py scientists.py rot13.txt count.py |
| 94 | +scientists.py □□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ (44) |
| 95 | +Files with thirteen lines are too scary! |
| 96 | +count.py □□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ (32) |
| 97 | +``` |
| 98 | + |
| 99 | +See [Asynchronous Task Groups in Python 3.11](https://realpython.com/python311-exception-groups/#asynchronous-task-groups-in-python-311) and [BPO 46752](https://github.com/python/cpython/pull/31270). |
| 100 | + |
| 101 | +### `tomllib` |
| 102 | + |
| 103 | +[`python_info.toml`](python_info.toml) and [`tomli_pyproject.toml`](tomli_pyproject.toml) show two examples of TOML files. |
| 104 | + |
| 105 | +Use [`read_toml.py`](read_toml.py) to read them: |
| 106 | + |
| 107 | +```console |
| 108 | +$ python read_toml.py python_info.toml tomli_pyproject.toml |
| 109 | +======================python_info.toml====================== |
| 110 | +{'python': {'version': 3.11, |
| 111 | + 'release_manager': 'Pablo Galindo Salgado', |
| 112 | + 'is_beta': True, |
| 113 | + 'beta_release': 3, |
| 114 | + 'release_date': datetime.date(2022, 6, 16), |
| 115 | + 'peps': [657, 654, 678, 680, 673, 675, 646, 659]}} |
| 116 | +====================tomli_pyproject.toml==================== |
| 117 | +{'build-system': {'requires': ['flit_core>=3.2.0,<4'], |
| 118 | + 'build-backend': 'flit_core.buildapi'}, |
| 119 | + 'project': {'name': 'tomli', |
| 120 | + 'version': '2.0.1', |
| 121 | + 'description': "A lil' TOML parser", |
| 122 | + 'requires-python': '>=3.7', |
| 123 | + 'readme': 'README.md', |
| 124 | + 'keywords': ['toml'], |
| 125 | + 'urls': {'Homepage': 'https://github.com/hukkin/tomli', |
| 126 | + 'PyPI': 'https://pypi.org/project/tomli'}}} |
| 127 | +``` |
| 128 | + |
| 129 | +[`tomllib_w.py`](tomllib_w.py) shows how you can write simplified TOML files: |
| 130 | + |
| 131 | +```pycon |
| 132 | +>>> import tomllib_w |
| 133 | +>>> data = {"url": "https://realpython.com/python311-tomllib/", |
| 134 | +... "author": { "name": "Geir Arne Hjelle", "email": "[email protected]"}} |
| 135 | + |
| 136 | +>>> print(tomllib_w.dumps(data)) |
| 137 | +url = "https://realpython.com/python311-tomllib/" |
| 138 | + |
| 139 | +[author] |
| 140 | +name = "Geir Arne Hjelle" |
| 141 | + |
| 142 | +``` |
| 143 | + |
| 144 | +See [`tomllib` TOML Parser in Python 3.11](https://realpython.com/python311-tomllib/#tomllib-toml-parser-in-python-311) and [PEP 680](https://peps.python.org/pep-0680/). |
| 145 | + |
| 146 | +### `Self` Type |
| 147 | + |
| 148 | +[`polar_point.py`](polar_point.py) uses `Self` for annotation: |
| 149 | + |
| 150 | +```console |
| 151 | +$ python polar_point.py |
| 152 | +PolarPoint(r=5.0, φ=0.9272952180016122) |
| 153 | +``` |
| 154 | + |
| 155 | +See [`Self` Type](https://realpython.com/python311-tomllib/#self-type) and [PEP 673](https://peps.python.org/pep-0673/). |
| 156 | + |
| 157 | +### Arbitrary `LiteralString` Type |
| 158 | + |
| 159 | +[`execute_sql.py`](execute_sql.py) shows an example of `LiteralString`: |
| 160 | + |
| 161 | +```console |
| 162 | +$ python execute_sql.py |
| 163 | +Pretending to execute: SELECT * FROM users |
| 164 | +Pretending to execute: SELECT * FROM users |
| 165 | + |
| 166 | +Enter table name: users; DROP TABLE users; -- |
| 167 | +Pretending to execute: SELECT * FROM users; DROP TABLE users; -- |
| 168 | +``` |
| 169 | + |
| 170 | +See [Arbitrary Literal String Type](https://realpython.com/python311-tomllib/#arbitrary-literal-string-type) and [PEP 675](https://peps.python.org/pep-0675/). |
| 171 | + |
| 172 | +### Variadic Generic Types: `TypeVarTuple` |
| 173 | + |
| 174 | +[`ndarray.py`](ndarray.py) shows an example of using `TypeVarTuple`. |
| 175 | + |
| 176 | +See [Variadic Generic Types](https://realpython.com/python311-tomllib/#variadic-generic-types) and [PEP 646](https://peps.python.org/pep-0646/). |
| 177 | + |
| 178 | +### Exception Annotations |
| 179 | + |
| 180 | +Use `.add_notes()` to annotate exceptions with custom notes: |
| 181 | + |
| 182 | +```pycon |
| 183 | +>>> err = ValueError(678) |
| 184 | +>>> err.add_note("Enriching Exceptions with Notes") |
| 185 | +>>> err.add_note("Python 3.11") |
| 186 | + |
| 187 | +>>> err.__notes__ |
| 188 | +['Enriching Exceptions with Notes', 'Python 3.11'] |
| 189 | +>>> for note in err.__notes__: |
| 190 | +... print(note) |
| 191 | +... |
| 192 | +Enriching Exceptions with Notes |
| 193 | +Python 3.11 |
| 194 | + |
| 195 | +>>> raise err |
| 196 | +Traceback (most recent call last): |
| 197 | + ... |
| 198 | +ValueError: 678 |
| 199 | +Enriching Exceptions with Notes |
| 200 | +Python 3.11 |
| 201 | +``` |
| 202 | + |
| 203 | +See [Annotate Exceptions With Custom Notes](https://realpython.com/python311-exception-groups/#annotate-exceptions-with-custom-notes) and [PEP 678](https://peps.python.org/pep-0678/). |
| 204 | + |
| 205 | +### Reference Active Exceptions |
| 206 | + |
| 207 | +You can use `sys.exception()` to access the active exception: |
| 208 | + |
| 209 | +```pycon |
| 210 | +>>> import sys |
| 211 | + |
| 212 | +>>> try: |
| 213 | +... raise ValueError("bpo-46328") |
| 214 | +... except ValueError: |
| 215 | +... print(f"Handling {sys.exception()}") |
| 216 | +... |
| 217 | +Handling bpo-46328 |
| 218 | +``` |
| 219 | + |
| 220 | +Note that this is typically not necessary in regular code. You can use the `except ValueError as err` syntax instead. |
| 221 | + |
| 222 | +See [Reference the Active Exception With `sys.exception()`](https://realpython.com/python311-exception-groups/#reference-the-active-exception-with-sysexception) and [BPO 46328](https://github.com/python/cpython/issues/90486). |
| 223 | + |
| 224 | +### Consistent Tracebacks |
| 225 | + |
| 226 | +`traceback_demo.py` shows that tracebacks can be consistently accessed through the exception object: |
| 227 | + |
| 228 | +```console |
| 229 | +$ python traceback_demo.py |
| 230 | +tb_last(exc_value.__traceback__) = 'bad_calculation:13' |
| 231 | +tb_last(exc_tb) = 'bad_calculation:13' |
| 232 | +``` |
| 233 | + |
| 234 | +See [Reference the Active Traceback Consistently](https://realpython.com/python311-exception-groups/#reference-the-active-traceback-consistently) and [BPO 45711](https://github.com/python/cpython/issues/89874). |
| 235 | + |
| 236 | +### New Math Functions: `cbrt()` and `exp2()` |
| 237 | + |
| 238 | +You can use `math.cbrt()` to calculate cube roots: |
| 239 | + |
| 240 | +```pycon |
| 241 | +>>> import math |
| 242 | +>>> math.cbrt(729) |
| 243 | +9.000000000000002 |
| 244 | + |
| 245 | +>>> 729**(1/3) |
| 246 | +8.999999999999998 |
| 247 | + |
| 248 | +>>> math.pow(729, 1/3) |
| 249 | +8.999999999999998 |
| 250 | +``` |
| 251 | + |
| 252 | +You can use `math.exp2()` to calculate powers of two: |
| 253 | + |
| 254 | +```pycon |
| 255 | +>>> import math |
| 256 | +>>> math.exp2(16) |
| 257 | +65536.0 |
| 258 | + |
| 259 | +>>> 2**16 |
| 260 | +65536 |
| 261 | + |
| 262 | +>>> math.pow(2, 16) |
| 263 | +65536.0 |
| 264 | +``` |
| 265 | + |
| 266 | +See [Cube Roots and Powers of Two](https://realpython.com/python311-error-messages/#cube-roots-and-powers-of-two), [BPO 44357](https://github.com/python/cpython/issues/88523) and [BPO 45917](https://github.com/python/cpython/issues/90075). |
| 267 | + |
| 268 | +### Underscores in Fractions |
| 269 | + |
| 270 | +You can use underscores when defining fractions from strings: |
| 271 | + |
| 272 | +```pycon |
| 273 | +>>> from fractions import Fraction |
| 274 | +>>> print(Fraction("6_024/1_729")) |
| 275 | +6024/1729 |
| 276 | +``` |
| 277 | + |
| 278 | +See [Underscores in Fractions](https://realpython.com/python311-error-messages/#underscores-in-fractions) and [BPO 44258](https://github.com/python/cpython/issues/88424). |
| 279 | + |
| 280 | +### Flexible Calling of Objects: `operator.call()` |
| 281 | + |
| 282 | +The Norwegian calculator implemented in [`kalkulator.py`](kalkulator.py) uses `operator.call()`: |
| 283 | + |
| 284 | +```pycon |
| 285 | +>>> import kalkulator |
| 286 | +>>> kalkulator.calculate("20 pluss 22") |
| 287 | +42.0 |
| 288 | + |
| 289 | +>>> kalkulator.calculate("11 delt på 3") |
| 290 | +3.6666666666666665 |
| 291 | +``` |
| 292 | + |
| 293 | +See [Flexible Calling of Objects](https://realpython.com/python311-error-messages/#flexible-calling-of-objects) and [BPO 44019](https://github.com/python/cpython/issues/88185). |
| 294 | + |
| 295 | +## Author |
| 296 | + |
| 297 | +- **Geir Arne Hjelle **, E-mail: [[email protected]]([email protected]) |
| 298 | + |
| 299 | +## License |
| 300 | + |
| 301 | +Distributed under the MIT license. See [`LICENSE`](../LICENSE) for more information. |
0 commit comments