尚未翻译
本页面尚未翻译成中文,因此显示英文原文。 帮助翻译
typing Module Complexity¶
The typing module provides support for type hints, allowing developers to annotate function parameters and return types for better code documentation and static analysis.
Complexity Reference¶
| Operation | Time | Space | Notes |
|---|---|---|---|
| Type annotation | O(1) | O(1) | Define hint (no runtime check) |
get_type_hints() |
O(k) | O(k) | k = number of annotations; involves string evaluation |
| Generic type creation | O(1) | O(1) | Create parameterized type |
Basic Type Hints¶
Function Annotations¶
from typing import Optional, List
# Type hints - O(1) (no runtime overhead)
def greet(name: str) -> str:
return f"Hello, {name}"
# Optional type - O(1)
def find_user(user_id: int) -> Optional[str]:
# May return str or None
if user_id == 1:
return "Alice"
return None
# List type - O(1)
def sum_numbers(nums: List[int]) -> int:
return sum(nums)
# Hints are just annotations, no enforcement
greet(123) # Works! (type checker would complain)
Common Types¶
from typing import Dict, Tuple, Set, Union
# Dict - key and value types - O(1)
def process_config(config: Dict[str, int]) -> None:
pass
# Tuple - element types - O(1)
def get_coordinates() -> Tuple[float, float]:
return (0.0, 1.0)
# Set - element type - O(1)
def get_unique_ids(data: List[str]) -> Set[str]:
return set(data)
# Union - multiple possible types - O(1)
def parse_input(value: Union[str, int]) -> str:
return str(value)
Generic Types¶
Generic Functions¶
from typing import TypeVar, Generic
# TypeVar - represents any type - O(1)
T = TypeVar('T')
# Generic function - O(1)
def first(items: List[T]) -> T:
return items[0]
# Usage - preserves type
numbers = [1, 2, 3]
first_num: int = first(numbers) # Typed as int
strings = ["a", "b"]
first_str: str = first(strings) # Typed as str
Generic Classes¶
from typing import Generic, TypeVar
# Type variable - O(1)
T = TypeVar('T')
# Generic class - O(1)
class Stack(Generic[T]):
def __init__(self):
self.items: List[T] = []
def push(self, item: T) -> None: # O(1)
self.items.append(item)
def pop(self) -> T: # O(1)
return self.items.pop()
# Usage
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
Callable Types¶
Function Types¶
from typing import Callable
# Callable type - O(1)
def apply_operation(a: int, b: int, op: Callable[[int, int], int]) -> int:
return op(a, b)
# Pass functions - O(1)
def add(x: int, y: int) -> int:
return x + y
result = apply_operation(5, 3, add) # 8
Higher-Order Functions¶
from typing import Callable, List
# Return function - O(1)
def create_multiplier(factor: int) -> Callable[[int], int]:
def multiply(x: int) -> int:
return x * factor
return multiply
# Usage
times_three = create_multiplier(3) # O(1)
result = times_three(5) # 15
Union and Optional¶
Union Types¶
from typing import Union
# Union - multiple types - O(1)
def process_value(value: Union[int, str, float]) -> None:
if isinstance(value, int):
print(f"Integer: {value}")
elif isinstance(value, str):
print(f"String: {value}")
else:
print(f"Float: {value}")
# Works with any of the types
process_value(42) # Integer
process_value("hello") # String
process_value(3.14) # Float
Optional (Union with None)¶
from typing import Optional
# Optional[T] is Union[T, None] - O(1)
def find_item(items: List[str], target: str) -> Optional[str]:
try:
return items[items.index(target)]
except ValueError:
return None
# Usage
result = find_item(["a", "b", "c"], "b") # str or None
Type Aliases¶
Creating Type Aliases¶
from typing import List, Tuple, Dict
# Type alias - O(1)
Coordinate = Tuple[float, float]
Grid = List[List[int]]
Config = Dict[str, str]
# Use aliases - cleaner code
def get_location() -> Coordinate:
return (0.0, 1.0)
def create_grid() -> Grid:
return [[1, 2], [3, 4]]
# Aliases improve readability
def load_config(path: str) -> Config:
return {"key": "value"}
Type Hints in Practice¶
Class Annotations¶
from typing import List, Optional
class User:
# Class-level annotations - O(1)
name: str
age: int
email: Optional[str]
def __init__(self, name: str, age: int, email: Optional[str] = None):
self.name = name
self.age = age
self.email = email
def get_info(self) -> str:
return f"{self.name} ({self.age})"
# Usage
user = User("Alice", 30, "alice@example.com")
Method Annotations¶
from typing import List
class DataProcessor:
def __init__(self):
self.data: List[int] = []
def add_value(self, value: int) -> None:
self.data.append(value)
def get_sum(self) -> int:
return sum(self.data)
def get_average(self) -> float:
if not self.data:
return 0.0
return self.get_sum() / len(self.data)
Runtime Type Checking¶
Getting Type Hints¶
from typing import get_type_hints
def add(a: int, b: int) -> int:
return a + b
# Get hints - O(k) where k = number of hints
hints = get_type_hints(add) # O(1)
# Result: {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
# Check hint
if hints.get('a') == int:
print("Parameter 'a' is int")
Runtime Enforcement¶
from typing import get_type_hints
def validate_types(func):
"""Decorator to check types at runtime - O(k)"""
hints = get_type_hints(func) # O(k)
def wrapper(*args, **kwargs):
# Check arguments - O(n) where n = number of args
for i, arg in enumerate(args):
arg_names = list(hints.keys())
if i < len(arg_names):
arg_name = arg_names[i]
expected_type = hints[arg_name]
# Note: isinstance() won't work for many typing constructs
if isinstance(expected_type, type) and not isinstance(arg, expected_type):
raise TypeError(f"{arg_name} must be {expected_type}")
return func(*args, **kwargs)
return wrapper
@validate_types
def add(a: int, b: int) -> int:
return a + b
add(5, 3) # OK
add(5, "3") # TypeError
Advanced Typing¶
Protocol (Structural Typing)¶
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
class Square:
def draw(self) -> None:
print("Drawing square")
def render(obj: Drawable) -> None:
obj.draw()
render(Circle()) # Works (implements draw)
render(Square()) # Works (implements draw)
Generic with Constraints¶
from typing import TypeVar
# TypeVar with constraints - O(1)
Number = TypeVar('Number', int, float)
def process_number(value: Number) -> Number:
return value * 2
process_number(5) # int
process_number(3.14) # float
# process_number("5") # Type error
Performance Considerations¶
Type Hints Have No Runtime Cost¶
# Type hints are annotations only (O(1) overhead)
def with_hints(x: int, y: int) -> int:
return x + y
def without_hints(x, y):
return x + y
# Both have identical performance
# Type hints don't add runtime overhead
Runtime Type Checking Can Be Expensive¶
# Simple check - O(1)
if isinstance(value, int):
pass
# Complex type check - O(n) for complex types
from typing import get_type_hints
hints = get_type_hints(func) # O(k) where k = number of hints
# Avoid repeated hint retrieval (cache it)
hints = get_type_hints(func) # O(k) once
for arg in args:
if isinstance(arg, hints['param']): # O(1) per check
pass
Best Practices¶
Code Examples¶
from typing import List, Optional, Dict, Callable
# Good: Clear types - O(1)
def process_data(
items: List[int],
processor: Callable[[int], int],
config: Optional[Dict[str, str]] = None
) -> List[int]:
"""Process items with given processor."""
return [processor(item) for item in items]
# Bad: No types
def process_data(items, processor, config=None):
"""Process items with given processor."""
return [processor(item) for item in items]
# Use type hints for better code documentation and IDE support
Related Modules¶
- dataclasses - Type hints for data classes
- collections.abc - Abstract base classes
Best Practices¶
✅ Do:
- Use type hints for function parameters and returns
- Use
Optional[T]for nullable values - Use generic types for collections
- Use type aliases for complex types
- Include type hints in public APIs
❌ Avoid:
- Over-annotating (use when helpful)
- Assuming type hints are enforced (they're not)
- Using
Anyexcessively (defeats purpose) - Enforcing types at runtime (performance cost)
- Forgetting that hints are documentation only