-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 3.12 examples from the typing preview (#438)
* Add 3.12 examples from the typing preview * Use Python 3.12 for linting * Upgrade Flake8 * Downgrade back to Python 3.11 for linting * Reset cache * Combine 3.11 and 3.12 code in the same file * Update README * README LE Static Typing --------- Co-authored-by: KateFinegan <[email protected]>
- Loading branch information
1 parent
0e7f7a4
commit e06ae43
Showing
14 changed files
with
290 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,10 @@ You can learn more about Python 3.12's new features in the following Real Python | |
- [Python 3.12 Preview: Ever Better Error Messages](https://realpython.com/python312-error-messages/) | ||
- [Python 3.12 Preview: Support For the Linux `perf` Profiler](https://realpython.com/python312-perf-profiler/) | ||
- [Python 3.12 Preview: More Intuitive and Consistent F-Strings](https://realpython.com/python312-f-strings/) | ||
- [Python 3.12 Preview: Subinterpreters](https://realpython.com/python312-subinterpreters/) | ||
- [Python 3.12 Preview: Static Typing Improvements](https://realpython.com/python312-typing/) | ||
|
||
You'll find examples from all these tutorials in this repository. | ||
You'll find examples from these tutorials in this repository. | ||
|
||
## Examples | ||
|
||
|
@@ -136,6 +138,37 @@ Pythonista! | |
|
||
In this example, you can see how the new implementation of f-strings allows you to include backslashes in embedded expressions. This wasn't possible with f-strings in earlier versions of Python. | ||
|
||
### Static Typing Improvements | ||
|
||
You'll find all static typing examples inside the [`typing/`](typing/) directory. You should install the Pyright type checker from PyPI: | ||
|
||
```console | ||
$ python -m pip install pyright | ||
``` | ||
|
||
You can then run type checks by running `pyright`. For some features, you need to specify `--pythonversion 3.12`. | ||
|
||
#### Type Variables and Generic Classes, Functions, and Type Aliases | ||
|
||
You can find comparisons between the old and the new syntax for type variables in the following files, with the new 3.12 syntax shown in the commented part of the code: | ||
|
||
- [`generic_queue.py`](typing/generic_queue.py) | ||
- [`list_helpers.py`](typing/list_helpers.py) | ||
- [`concatenation.py`](typing/concatenation.py) | ||
- [`inspect_string.py`](typing/inspect_string.py) | ||
- [`deck.py`](typing/deck.py) | ||
- [`alias.py`](typing/alias.py) | ||
|
||
Additionally, [`typed_queue.py`](typing/typed_queue.py) shows the implementation of typed queues without using type variables. | ||
|
||
#### Modeling Inheritance With `@override` | ||
|
||
The file [`quiz.py`](typing/quiz.py) shows how to use the new `@override` decorator. In addition to the code in the tutorial, this file includes support for reading questions from files. This is done to show that `@override` works well together with other decorators like `@classmethod`. | ||
|
||
#### Annotating `**kwargs` With Typed Dictionaries | ||
|
||
The file [`options.py`](typing/options.py) shows how you can use a typed dictionary to annotate variable keyword arguments. | ||
|
||
## Authors | ||
|
||
- **Martin Breuss**, E-mail: [[email protected]]([email protected]) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from typing import TypeAlias, TypeVar | ||
|
||
T = TypeVar("T") | ||
|
||
Ordered: TypeAlias = list[T] | tuple[T, ...] | ||
|
||
numbers: Ordered[int] = (1, 2, 3) | ||
|
||
|
||
# %% Python 3.12 | ||
|
||
# type Ordered[T] = list[T] | tuple[T, ...] | ||
# | ||
# numbers: Ordered[int] = (1, 2, 3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from typing import TypeVar | ||
|
||
T = TypeVar("T", str, bytes) | ||
|
||
|
||
def concatenate(first: T, second: T) -> T: | ||
return first + second | ||
|
||
|
||
# %% Python 3.12 | ||
|
||
# def concatenate[T: (str, bytes)](first: T, second: T) -> T: | ||
# return first + second |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import random | ||
from typing import TypeAlias | ||
|
||
CardDeck: TypeAlias = list[tuple[str, int]] | ||
|
||
|
||
def shuffle(deck: CardDeck) -> CardDeck: | ||
return random.sample(deck, k=len(deck)) | ||
|
||
|
||
# %% Python 3.12 | ||
|
||
# import random | ||
# | ||
# type CardDeck = list[tuple[str, int]] | ||
# | ||
# def shuffle(deck: CardDeck) -> CardDeck: | ||
# return random.sample(deck, k=len(deck)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from collections import deque | ||
from typing import Generic, TypeVar | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
class Queue(Generic[T]): | ||
def __init__(self) -> None: | ||
self.elements: deque[T] = deque() | ||
|
||
def push(self, element: T) -> None: | ||
self.elements.append(element) | ||
|
||
def pop(self) -> T: | ||
return self.elements.popleft() | ||
|
||
|
||
# %% Python 3.12 | ||
|
||
# from collections import deque | ||
# | ||
# | ||
# class Queue[T]: | ||
# def __init__(self) -> None: | ||
# self.elements: deque[T] = deque() | ||
# | ||
# def push(self, element: T) -> None: | ||
# self.elements.append(element) | ||
# | ||
# def pop(self) -> T: | ||
# return self.elements.popleft() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from typing import TypeVar | ||
|
||
S = TypeVar("S", bound=str) | ||
|
||
|
||
class Words(str): | ||
def __len__(self): | ||
return len(self.split()) | ||
|
||
|
||
def inspect(text: S) -> S: | ||
print(f"'{text.upper()}' has length {len(text)}") | ||
return text | ||
|
||
|
||
# %% Python 3.12 | ||
|
||
# class Words(str): | ||
# def __len__(self): | ||
# return len(self.split()) | ||
# | ||
# | ||
# def inspect[S: str](text: S) -> S: | ||
# print(f"'{text.upper()}' has length {len(text)}") | ||
# return text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from typing import TypeVar | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
def push_and_pop(elements: list[T], element: T) -> T: | ||
elements.append(element) | ||
return elements.pop(0) | ||
|
||
|
||
# %% Python 3.12 | ||
|
||
# def push_and_pop[T](elements: list[T], element: T) -> T: | ||
# elements.append(element) | ||
# return elements.pop(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from typing import Required, TypedDict, Unpack | ||
|
||
|
||
class Options(TypedDict, total=False): | ||
line_width: int | ||
level: Required[str] | ||
propagate: bool | ||
|
||
|
||
def show_options(program_name: str, **kwargs: Unpack[Options]) -> None: | ||
print(program_name.upper()) | ||
for option, value in kwargs.items(): | ||
print(f"{option:<15} {value}") | ||
|
||
|
||
def show_options_explicit( | ||
program_name: str, | ||
*, | ||
level: str, | ||
line_width: int | None = None, | ||
propagate: bool | None = None, | ||
) -> None: | ||
options = { | ||
"line_width": line_width, | ||
"level": level, | ||
"propagate": propagate, | ||
} | ||
print(program_name.upper()) | ||
for option, value in options.items(): | ||
if value is not None: | ||
print(f"{option:<15} {value}") | ||
|
||
|
||
show_options("logger", line_width=80, level="INFO", propagate=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
In which country is Oslo the capital? | ||
Norway | ||
Sweden | ||
Ireland | ||
Canada |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[tool.pyright] | ||
# reportImplicitOverride = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import pathlib | ||
import random | ||
from dataclasses import dataclass | ||
from string import ascii_lowercase | ||
from typing import Self, override | ||
|
||
|
||
@dataclass | ||
class Question: | ||
question: str | ||
answer: str | ||
|
||
@classmethod | ||
def from_file(cls, path: pathlib.Path) -> Self: | ||
question, answer, *_ = path.read_text(encoding="utf-8").split("\n") | ||
return cls(question, answer) | ||
|
||
def ask(self) -> bool: | ||
answer = input(f"\n{self.question} ") | ||
return answer == self.answer | ||
|
||
|
||
@dataclass | ||
class MultipleChoiceQuestion(Question): | ||
distractors: list[str] | ||
|
||
@classmethod | ||
@override | ||
def from_file(cls, path: pathlib.Path) -> Self: | ||
question, answer, *distractors = ( | ||
path.read_text(encoding="utf-8").strip().split("\n") | ||
) | ||
return cls(question, answer, distractors) | ||
|
||
@override | ||
def ask(self) -> bool: | ||
print(f"\n{self.question}") | ||
|
||
alternatives = random.sample( | ||
self.distractors + [self.answer], k=len(self.distractors) + 1 | ||
) | ||
labeled_alternatives = dict(zip(ascii_lowercase, alternatives)) | ||
for label, alternative in labeled_alternatives.items(): | ||
print(f" {label}) {alternative}", end="") | ||
|
||
answer = input("\n\nChoice? ") | ||
return labeled_alternatives.get(answer) == self.answer | ||
|
||
|
||
questions = [ | ||
Question("Who created Python?", "Guido van Rossum"), | ||
MultipleChoiceQuestion( | ||
"What's a PEP?", | ||
"A Python Enhancement Proposal", | ||
distractors=[ | ||
"A Pretty Exciting Policy", | ||
"A Preciously Evolved Python", | ||
"A Potentially Epic Prize", | ||
], | ||
), | ||
MultipleChoiceQuestion.from_file(pathlib.Path("oslo.question")), | ||
] | ||
|
||
score = 0 | ||
for question in random.sample(questions, k=len(questions)): | ||
if question.ask(): | ||
score += 1 | ||
print("Yes, that's correct!") | ||
else: | ||
print(f"No, the answer is '{question.answer}'") | ||
|
||
print(f"\nYou got {score} out of {len(questions)} correct") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from collections import deque | ||
|
||
|
||
class IntegerQueue: | ||
def __init__(self) -> None: | ||
self.elements: deque[int] = deque() | ||
|
||
def push(self, element: int) -> None: | ||
self.elements.append(element) | ||
|
||
def pop(self) -> int: | ||
return self.elements.popleft() | ||
|
||
|
||
class StringQueue: | ||
def __init__(self) -> None: | ||
self.elements: deque[str] = deque() | ||
|
||
def push(self, element: str) -> None: | ||
self.elements.append(element) | ||
|
||
def pop(self) -> str: | ||
return self.elements.popleft() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
black[jupyter]==22.6.0 | ||
flake8==5.0.4 | ||
flake8==6.1.0 |