Beware! A new Python is approaching!

Overview

Structural Pattern Matching

Pattern Matching example 1

def analyze_input_from_user():
text = input("Enter some text: ")
match text.split():
case []:
print("Got nothing")
case [("add" | "subtract") as cmd, a, b]:
print(f"Got operation {cmd} with parameters {a} and {b}")
case [x] if x.isdigit():
number = int(x)
print(f"Got a single integer number: {number}")
case [x] if re.match(r"^[+-]?\\d+(.\\d*)?$", x):
number = float(x)
print(f"Got a single floating point number: {number:.3f}")
case [word]: # Must be non-numeric, since numerics are matched above
print(f"Got a single non-numeric word: {word}")
case _:
print("Got something else")
def analyze_input_from_user_the_old_way():
text = input("Enter some text: ")
words = text.split()
if len(words) == 0:
print("Got nothing")
elif len(words) == 3 and words[0] in ["add", "subtract"]:
(cmd, a, b) = words
print(f"Got operation {cmd} with parameters {a} and {b}")
elif len(words) == 1 and words[0].isdigit():
number = int(words[0])
print(f"Got a single integer number: {number}")
elif len(words) == 1 and re.match(r"^[+-]?\\d+(.\\d*)?$", words[0]):
number = float(words[0])
print(f"Got a single floating point number: {number:.3f}")
elif len(words) == 1:
word = words[0]
print(f"Got a single non-numeric word: {word}")
else:
print("Got something else")

Pattern matching example 2

issues = [
{
'issuer': "Mr Praline",
'date': date(1969, 12, 7),
'type': 'complaint',
'title': "a Dead Parrot",
},
{
'issuer': "A man",
'date': date(1972, 11, 2),
'type': 'request',
'subject': "an argument",
'location': "the Argument Clinic",
},
"Now something completely different",
]
def print_info_about_issues():
for issue in issues:
print_info_about_issue(issue)
def print_info_about_issue(issue):
match issue:
case {'type': 'complaint', 'date': d, 'title': t, 'issuer': i}:
print(f"{i} complained about {t} on {d}.")
case {
'type': 'request',
'date': date(year=y),
'subject': s,
'location': l,
'issuer': i,
}:
print(f"{i} requested to have {s} on {y} at {l}.")
case str(text):
print(f"Textual issue: {text}")
def print_info_about_issue_the_old_way(issue):
if isinstance(issue, dict) and (
issue.get('type') == 'complaint' and
'date' in issue and 'title' in issue and 'issuer' in issue):
d = issue['date']
t = issue['title']
i = issue['issuer']
print(f"{i} complained about {t} on {d}.")
elif isinstance(issue, dict) and (
issue.get('type') == 'request' and
isinstance(issue.get('date'), date) and
'subject' in issue and 'location' in issue and 'issuer' in issue):
y = issue['date'].year
s = issue['subject']
l = issue['location']
i = issue['issuer']
print(f"{i} requested to have {s} on {y} at {l}.")
elif isinstance(issue, str):
print(f"Textual issue: {issue}")

Tool support

More pattern matching

Typing related improvements

Writing Union types as X | Y

from decimal import Decimaldef format_euros(value: float | Decimal | None) -> str | None:
if value is None:
return None
return '{:.2f} €'.format(value)
from decimal import Decimal
from typing import Optional, Union
def format_euros_old(value: Optional[Union[float, Decimal]]) -> Optional[str]:
if value is None:
return None
return '{:.2f} €'.format(value)
assert isinstance(3.5, float | None)
assert issubclass(bool, int | str) # since bool is subclass of int
assert not isinstance("3.10", float | int | bytes)

Parameter Specification Variables

from typing import Callable, ParamSpec, TypeVarP = ParamSpec("P")
R = TypeVar("R")
measured_times: dict[str, float] = {}def time_measured(f: Callable[P, R]) -> Callable[P, R]:
def inner(*args: P.args, **kwargs: P.kwargs) -> R:
t0 = time.perf_counter()
result = f(*args, **kwargs)
t1 = time.perf_counter()
measured_times[f.__name__] = t1 - t0
return result
return inner
@time_measured
def repeated_string(a: str, n: int) -> str:
return a * n
repeated_string("ABC", 123) # This is OK
repeated_string(123, "ABC") # This should be rejected by type checker

Explicit Type Aliases

TreeMap = "dict[str, Tree]"class Tree:
def __init__(self, subtrees: TreeMap) -> None:
self.subtrees = subtrees
from typing_extensions import TypeAliasTreeMap: TypeAlias = "dict[str, Tree]"class Tree:
def __init__(self, subtrees: TreeMap) -> None:
self.subtrees = subtrees

Postponed evaluation of annotations

Should I already update?

--

--

--

Anders is a Finnish IT company, whose mission is sustainable software development with the greatest colleagues of all time.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Where do bugs thrive?

Build it; Clone it;— An Apollo Federated API — Pt. 2: The Comprehensive Apollo Subgraph Starter

Apollo Lander on the Moon

Implementing K-Nearest Neighbors in scikit-learn

Story of a Quarantine Video Call

Server-side Swift: Making Canopy (2/6)

Kubernetes Basic Tutorial-1

The Difference Between Getting Things Done and Making Things Last In Software Engineering

Ever since I was a little boy, I have only ever wanted to be a Doctor.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Anders Innovations

Anders Innovations

Anders is a Finnish IT company, whose mission is sustainable software development with the greatest colleagues of all time.

More from Medium

Installing Pycharm (advanced IDE for working on coding projects)-Community Version

Using the U.S. Census Bureau API with Python

End of the Road for Python 3.6 — What’s Next

Timedelta-python