Skip to content

Python 3.9 - Complexity & Features

Python 3.9 was released October 2020 with improved type hinting and optimizations.

Major Features

Type Hints Without Imports

# Python 3.9+: Use built-in types for type hints
def process(items: list[int]) -> dict[str, int]:
    return {str(i): i for i in items}

# Before 3.9: Required imports
from typing import List, Dict

def process(items: List[int]) -> Dict[str, int]:
    return {str(i): i for i in items}

Dictionary Operations

# Merge and update operators for dicts (PEP 584)
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3}

# Merge (non-mutating)
d3 = d1 | d2  # {'a': 1, 'b': 2, 'c': 3}

# Update (mutating)
d1 |= d2  # d1 now {'a': 1, 'b': 2, 'c': 3}

# Same as:
# d3 = {**d1, **d2}  (3.5+)
# d1.update(d2)

Flexible Function Decorators

# Can use expressions as decorators
buttons = [button1, button2, button3]

# Python 3.9: Cleaner syntax
@buttons[0].clicked.connect
def on_button_clicked():
    pass

# Instead of:
# decorator = buttons[0].clicked.connect
# @decorator
# def on_button_clicked():
#     pass

Performance Characteristics

Comparable to Python 3.8

Performance improvements modest from 3.8:

# 3.9 vs 3.8: Similar speed
# New features have minimal overhead

Complexity Unchanged

All data structure complexities same as 3.8:

Type Operation Complexity
list append O(1) amortized
list insert O(n)
dict lookup O(1) avg
dict insert O(1) avg
set add O(1) amortized
str find O(n*m)

Data Structure Examples

Dictionary Merge

# Union operator (|) for dicts
config_default = {
    'timeout': 30,
    'retries': 3,
    'debug': False
}

config_user = {
    'timeout': 60,
    'debug': True
}

# Combine configs
config = config_default | config_user
# {'timeout': 60, 'retries': 3, 'debug': True}

# Same complexity as unpacking
# config = {**config_default, **config_user}  # O(n+m)

List Type Hints

# Cleaner type hints
def process_numbers(nums: list[int]) -> list[int]:
    """Process a list of integers."""
    return [n * 2 for n in nums]

def get_mapping(keys: list[str]) -> dict[str, int]:
    """Create mapping from keys."""
    return {k: i for i, k in enumerate(keys)}

# More readable than typing.List, typing.Dict

Standard Library Changes

Graph Changes

ZoneInfo module for timezone support:

from zoneinfo import ZoneInfo
from datetime import datetime

# Better timezone handling
dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))

Deprecations

Some modules marked for removal:

# These modules deprecated (removed in 3.11+):
# - aifc, audioop, chunk, cgi, cgitb, imaplib, mailcap
# - nis, nntplib, spwd, sunau, xdrlib

# Plan migrations if using these

Examples and Patterns

Pattern: Configuration Merge

# Pre-3.9: verbose
defaults = {'a': 1, 'b': 2}
overrides = {'b': 3, 'c': 4}
config = {**defaults, **overrides}

# 3.9+: cleaner
config = defaults | overrides  # {'a': 1, 'b': 3, 'c': 4}

Pattern: Multiple Inheritance with MRO

Type hints improved for complex inheritance:

class Animal:
    pass

class Flyer:
    pass

class Bird(Animal, Flyer):
    pass

def process(b: Bird) -> None:
    pass

# Type hints clearer without importing from typing

Memory and Performance

String Changes

Python 3.9 optimized string representation:

# Flexible string representation (from 3.3) further optimized
s = "hello"  # ASCII: 1 byte per char
s = "こんにちは"  # Multi-byte: 2 bytes per char

# More efficient than 4-byte per char in older Python

Compatibility

Minimal Breaking Changes

Very safe upgrade from 3.8:

# Almost all code works unchanged
# New features are optional
# No major complexity changes

New in 3.9

# New features (optional):
# 1. Type hints without imports: list[int]
# 2. Dict merge: d1 | d2
# 3. Flexible function decorators
# 4. Better error messages

Recommendations

When to Use Python 3.9

Good for: - ✅ New projects (nice type hint syntax) - ✅ Long-term support (EOL October 2025) - ✅ Stable baseline (well-tested)

Better choices: - 3.11+ if performance critical - 3.10+ for pattern matching - 3.8 if compatibility paramount

Performance Considerations

Python 3.9 adequate for most workloads:

# Performance improvements over 3.8 modest
# Focus on algorithmic optimization first
# Upgrade to 3.11 if performance critical

Upgrade Path

From Python 3.8

# Test with 3.9
pyenv install 3.9.x
pyenv shell 3.9.x
pytest  # Run tests

# Usually works without changes
# Update type hints to use new syntax (optional)

Code Updates (Optional)

# Old style (still works in 3.9+)
from typing import List, Dict
def func(items: List[int]) -> Dict[str, int]:
    pass

# New style (preferred in 3.9+)
def func(items: list[int]) -> dict[str, int]:
    pass