-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add examples from Python 3.13: Cool New Features #587
Merged
+333
−1
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ Note that for testing the free-threading and JIT features, you'll need to build | |
|
||
You can learn more about Python 3.13's new features in the following Real Python tutorials: | ||
|
||
<!-- - [Python 3.13: Cool New Features for You to Try](https://realpython.com/python313-new-features/) --> | ||
- [Python 3.13: Cool New Features for You to Try](https://realpython.com/python313-new-features/) | ||
- [Python 3.13 Preview: Free Threading and a JIT Compiler](https://realpython.com/python313-free-threading-jit/) | ||
- [Python 3.13 Preview: A Modern REPL](https://realpython.com/python313-repl) | ||
|
||
|
@@ -30,11 +30,28 @@ The following examples are used to demonstrate different features of the new REP | |
- [`multiline_editing.py`](repl/multiline_editing.py) | ||
- [`power_factory.py](repl/power_factory.py) | ||
- [`guessing_game.py](repl/guessing_game.py) | ||
- [`roll_dice.py`](repl/roll_dice.py) | ||
|
||
### Error messages | ||
|
||
Run the scripts in the `errors/` folder to see different error messages produced by Python 3.13. | ||
|
||
### Free-Threading and JIT | ||
|
||
You need to enable a few build options to try out the free-threading and JIT features in Python 3.13. You can find more information in the dedicated [README file](free-threading-jit/README.md). | ||
|
||
## Static typing | ||
|
||
Run the scripts in the `typing/` folder to try out the new static typing features. | ||
|
||
## Other features | ||
|
||
The following scripts illustrate other new features in Python 3.13: | ||
|
||
- [`replace.py`](replace.py): Use `copy.replace()` to update immutable data structures. | ||
- [`paths.py`](paths.py) and [`music/`](music/): Glob patterns are more consistent. | ||
- [`docstrings.py`](docstrings.py): Common leading whitespace in docstrings is stripped. | ||
|
||
## Authors | ||
|
||
- **Bartosz Zaczyński**, 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,16 @@ | ||
import dataclasses | ||
|
||
|
||
@dataclasses.dataclass | ||
class Person: | ||
"""Model a person with a name, location, and Python version.""" | ||
|
||
name: str | ||
place: str | ||
version: str | ||
|
||
|
||
print(Person.__doc__) | ||
|
||
print(len(dataclasses.replace.__doc__)) | ||
print(dataclasses.replace.__doc__) |
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 @@ | ||
def inverse(number): | ||
return 1 / number | ||
|
||
|
||
print(inverse(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,4 @@ | ||
numbers = [2, 0, 2, 4, 1, 0, 0, 1] | ||
|
||
# print(sorted(numbers, reversed=True)) | ||
print(sorted(numbers, reverse=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,14 @@ | ||
import random | ||
|
||
num_faces = 6 | ||
|
||
print("Hit enter to roll die (q to quit, number for # of faces) ") | ||
while True: | ||
roll = input() | ||
if roll.lower().startswith("q"): | ||
break | ||
if roll.isnumeric(): | ||
num_faces = int(roll) | ||
|
||
result = random.randint(1, num_faces) | ||
print(f"Rolling a d{num_faces:<2d} - {result:2d}") |
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
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,27 @@ | ||
import glob | ||
import re | ||
from pathlib import Path | ||
|
||
print('\nUsing glob("*"):\n') | ||
for path in Path("music").glob("*"): | ||
print(" ", path) | ||
|
||
print('\nUsing glob("**"):\n') | ||
for path in Path("music").glob("**"): | ||
print(" ", path) | ||
|
||
print('\nUsing glob("**/*"):\n') | ||
for path in Path("music").glob("**/*"): | ||
print(" ", path) | ||
|
||
print('\nUsing glob("**/"):\n') | ||
for path in Path("music").glob("**/"): | ||
print(" ", path) | ||
|
||
print("\nglob.translate()\n") | ||
pattern = glob.translate("music/**/*.txt") | ||
print(pattern) | ||
|
||
print(re.match(pattern, "music/opera/flower_duet.txt")) | ||
print(re.match(pattern, "music/progressive_rock/")) | ||
print(re.match(pattern, "music/progressive_rock/fandango.txt")) |
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 @@ | ||
import random | ||
|
||
num_faces = 6 | ||
|
||
print("Hit enter to roll die (q to quit, number for # of faces) ") | ||
while True: | ||
roll = input() | ||
if roll.lower().startswith("q"): | ||
break | ||
if roll.isnumeric(): | ||
num_faces = int(roll) | ||
|
||
result = random.randint(1, num_faces) | ||
print(f"Rolling a d{num_faces:<2d} - {result:2d}") |
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 @@ | ||
import copy | ||
from datetime import date | ||
from typing import NamedTuple | ||
|
||
|
||
class Person(NamedTuple): | ||
name: str | ||
place: str | ||
version: str | ||
|
||
|
||
person = Person(name="Geir Arne", place="Oslo", version="3.12") | ||
person = Person(name=person.name, place=person.place, version="3.13") | ||
print(person) | ||
|
||
today = date.today() | ||
print(today) | ||
print(today.replace(day=1)) | ||
print(today.replace(month=12, day=24)) | ||
|
||
person = Person(name="Geir Arne", place="Oslo", version="3.12") | ||
print(copy.replace(person, version="3.13")) | ||
print(copy.replace(today, day=1)) |
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,82 @@ | ||
"""Demonstration of PEP 702: Marking deprecations using the type system | ||
|
||
The deprecations should be marked in PyCharm and VS Code. | ||
|
||
Use PyLance in VS Code by setting Python › Analysis: Type Checking Mode or run | ||
the Pyright CLI: | ||
|
||
$ python -m pip install pyright | ||
$ pyright --pythonversion 3.13 . | ||
|
||
Note that showing warnings with Pyright requires setting the reportDeprecated | ||
option. This is done in the accompanying pyproject.toml. | ||
""" | ||
|
||
from typing import overload | ||
from warnings import deprecated | ||
|
||
|
||
@deprecated("Use + instead of calling concatenate()") | ||
def concatenate(first: str, second: str) -> str: | ||
return first + second | ||
|
||
|
||
@overload | ||
@deprecated("add() is only supported for floats") | ||
def add(x: int, y: int) -> int: ... | ||
@overload | ||
def add(x: float, y: float) -> float: ... | ||
|
||
|
||
def add(x, y): | ||
return x + y | ||
|
||
|
||
class Version: | ||
def __init__(self, major: int, minor: int = 0, patch: int = 0) -> None: | ||
self.major = major | ||
self.minor = minor | ||
self.patch = patch | ||
|
||
@property | ||
@deprecated("Use .patch instead") | ||
def bugfix(self): | ||
return self.patch | ||
|
||
def bump(self, part: str) -> None: | ||
if part == "major": | ||
self.major += 1 | ||
self.minor = 0 | ||
self.patch = 0 | ||
elif part == "minor": | ||
self.minor += 1 | ||
self.patch = 0 | ||
elif part == "patch": | ||
self.patch += 1 | ||
else: | ||
raise ValueError("part must be 'major', 'minor', or 'patch'") | ||
|
||
@deprecated("Use .bump() instead") | ||
def increase(self, part: str) -> None: | ||
return self.bump(part) | ||
|
||
def __str__(self): | ||
return f"{self.major}.{self.minor}.{self.patch}" | ||
|
||
|
||
@deprecated("Use Version instead") | ||
class VersionType: | ||
def __init__(self, major: int, minor: int = 0, patch: int = 0) -> None: | ||
self.major = major | ||
self.minor = minor | ||
self.patch = patch | ||
|
||
|
||
concatenate("three", "thirteen") | ||
add(3, 13) | ||
VersionType(3, 13) | ||
|
||
version = Version(3, 13) | ||
version.increase("patch") | ||
print(version) | ||
print(version.bugfix) | ||
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,38 @@ | ||
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() | ||
|
||
|
||
# %% Python 3.13 | ||
# | ||
# class Queue[T=str]: | ||
# 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() | ||
|
||
# %% Use the queue | ||
# | ||
string_queue = Queue() | ||
integer_queue = Queue[int]() | ||
|
||
string_queue.push("three") | ||
string_queue.push("thirteen") | ||
print(string_queue.elements) | ||
|
||
integer_queue.push(3) | ||
integer_queue.push(13) | ||
print(integer_queue.elements) |
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] | ||
reportDeprecated = 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,56 @@ | ||
"""Demonstration of PEP 705: TypedDict: read-only items | ||
|
||
Use PyLance in VS Code by setting Python › Analysis: Type Checking Mode or run | ||
the Pyright CLI: | ||
|
||
$ python -m pip install pyright $ pyright --pythonversion 3.13 . | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these two commands be on separate lines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, yes, definitely. It seems that the automatic comment formatter I ran is a bit eager. |
||
|
||
Extension of TypedDict: | ||
https://realpython.com/python38-new-features/#more-precise-types | ||
""" | ||
|
||
from typing import NotRequired, ReadOnly, TypedDict | ||
|
||
# %% Without ReadOnly | ||
|
||
# class Version(TypedDict): | ||
# version: str | ||
# release_year: NotRequired[int | None] | ||
|
||
|
||
# class PythonVersion(TypedDict): | ||
# version: str | ||
# release_year: int | ||
|
||
|
||
# %% Using ReadOnly | ||
# | ||
# Can only use PythonVersion as a Version if the differing fields are ReadOnly | ||
class Version(TypedDict): | ||
version: str | ||
release_year: ReadOnly[NotRequired[int | None]] | ||
bzaczynski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Note that ReadOnly can be nested with other special forms in any order | ||
# release_year: NotRequired[ReadOnly[int | None]] | ||
|
||
|
||
class PythonVersion(TypedDict): | ||
version: str | ||
release_year: ReadOnly[int] | ||
|
||
|
||
# %% Work with Version and PythonVersion | ||
# | ||
def get_version_info(ver: Version) -> str: | ||
if "release_year" in ver: | ||
return f"Version {ver['version']} released in {ver['release_year']}" | ||
else: | ||
return f"Version {ver['version']}" | ||
|
||
|
||
py313 = PythonVersion(version="3.13", release_year=2024) | ||
|
||
# Alternative syntax, using TypedDict as an annotation | ||
# py313: PythonVersion = {"version": "3.13", "release_year": 2024} | ||
|
||
print(get_version_info(py313)) |
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 TypeGuard | ||
|
||
type Tree = list[Tree | int] | ||
|
||
|
||
def is_tree(obj: object) -> TypeGuard[Tree]: | ||
return isinstance(obj, list) | ||
|
||
|
||
def get_left_leaf_value(tree_or_leaf: Tree | int) -> int: | ||
if is_tree(tree_or_leaf): | ||
return get_left_leaf_value(tree_or_leaf[0]) | ||
else: | ||
return tree_or_leaf | ||
|
||
|
||
# %% Python 3.13 | ||
# | ||
# from typing import TypeIs | ||
# | ||
# type Tree = list[Tree | int] | ||
# | ||
# def is_tree(obj: object) -> TypeIs[Tree]: | ||
# return isinstance(obj, list) | ||
# | ||
# def get_left_leaf_value(tree_or_leaf: Tree | int) -> int: | ||
# if is_tree(tree_or_leaf): | ||
# return get_left_leaf_value(tree_or_leaf[0]) | ||
# else: | ||
# return tree_or_leaf | ||
|
||
# %% Use the tree | ||
# | ||
print(get_left_leaf_value([[[[3, 13], 12], 11], 10])) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PyCharm is smart enough to recognize the new decorator and uses strike-through formatting:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. Yes, that looks quite similar to VS Code. I'll add PyCharm to the top comment.