
Python
Master type hints, isinstance() checks, safe conversion patterns, and the typing module for robust code.
Type hints document what types functions expect and return. Python's type checker mypy can verify them.
# Basic type hints
def greet(name: str) -> str:
"""Greet someone by name."""
return f"Hello, {name}!"
print(greet("Alice")) # OK
print(greet(42)) # Type checker warns, but runs fine (no enforcement)
# Multiple parameters
def add(a: int, b: int) -> int:
return a + b
# Variable type hints
count: int = 0
message: str = "Hello"
items: list = []
# Complex types
from typing import List, Dict, Optional, Union, Tuple
def process_names(names: List[str]) -> Dict[str, int]:
"""Map names to their lengths."""
return {name: len(name) for name in names}
def find_item(items: List[str], target: str) -> Optional[int]:
"""Find index of target, or None if not found."""
try:
return items.index(target)
except ValueError:
return None
# Union types: accepts multiple types
def stringify(value: Union[int, float, str]) -> str:
return str(value)
# Tuple with fixed types
def get_coordinates() -> Tuple[float, float]:
return 3.14, 2.71from typing import List, Dict, Set, Tuple, Optional, Union, Callable, Any
# Collections
numbers: List[int] = [1, 2, 3]
mapping: Dict[str, int] = {"a": 1, "b": 2}
unique: Set[str] = {"apple", "banana"}
pair: Tuple[str, int] = ("Alice", 30)
# Optional: can be None
user_id: Optional[int] = None
user_id = 42 # OK
# Union: multiple possible types
response: Union[str, int] = "success"
response = 200 # Also OK
# Callable: function types
callback: Callable[[int, int], int] = lambda x, y: x + y
print(callback(3, 4)) # 7
# Any: accept anything (use sparingly)
value: Any = "anything goes"
value = 42
value = [1, 2, 3]
# Generic types (Python 3.9+)
def first_element(items: list[str]) -> str:
"""Return first element from list of strings."""
return items[0]
# Protocol for structural typing (duck typing with type hints)
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 draw_shape(shape: Drawable) -> None:
shape.draw()
draw_shape(Circle()) # OK (has draw method)
draw_shape(Square()) # OK (has draw method)# isinstance(): Check if object is instance of class/type
x = 42
print(isinstance(x, int)) # True
print(isinstance(x, (int, float))) # True (check multiple)
# Type vs isinstance
print(type(x) == int) # True
print(type(x) is int) # True (same object)
print(isinstance(x, int)) # True
# Difference with inheritance
class Animal:
pass
class Dog(Animal):
pass
d = Dog()
print(type(d) == Dog) # True
print(type(d) == Animal) # False
print(isinstance(d, Dog)) # True
print(isinstance(d, Animal)) # True ← isinstance follows inheritanceUse `isinstance()` instead of `type()` for better polymorphism:
# ✗ Wrong: doesn't work with subclasses
def process(obj):
if type(obj) == list:
return len(obj)
elif type(obj) == str:
return obj.upper()
# ✓ Right: works with subclasses
def process(obj):
if isinstance(obj, list):
return len(obj)
elif isinstance(obj, str):
return obj.upper()# Pattern 1: Try-except for safe conversion
def safe_int(value):
try:
return int(value)
except ValueError:
return None
print(safe_int("42")) # 42
print(safe_int("not_int")) # None
# Pattern 2: Type validation before conversion
def validate_and_convert(value, target_type):
if isinstance(value, target_type):
return value # Already correct type
if isinstance(value, str):
try:
return target_type(value)
except (ValueError, TypeError):
raise TypeError(f"Cannot convert {value!r} to {target_type.__name__}")
raise TypeError(f"Expected str or {target_type.__name__}")
print(validate_and_convert("42", int)) # 42
print(validate_and_convert(42, int)) # 42
# validate_and_convert(42.5, int) # TypeError
# Pattern 3: Explicit type checking in functions
def process_data(data: Union[List[int], Dict[str, int]]) -> int:
if isinstance(data, list):
return sum(data)
elif isinstance(data, dict):
return sum(data.values())
else:
raise TypeError(f"Unexpected type: {type(data)}")
print(process_data([1, 2, 3])) # 6
print(process_data({"a": 10, "b": 20})) # 30
# Pattern 4: Using type() for dynamic conversion
converters = {
'int': int,
'float': float,
'str': str,
'bool': bool,
}
def flexible_convert(value, type_name):
if type_name not in converters:
raise ValueError(f"Unknown type: {type_name}")
return converters[type_name](value)
print(flexible_convert("42", "int")) # 42
print(flexible_convert("3.14", "float")) # 3.14# Install mypy
pip install mypy
# Check your code
mypy script.pyExample with type errors:
# script.py
def add(x: int, y: int) -> int:
return x + y
result = add(5, "10") # mypy error: argument is string, not int
print(result)Running mypy detects the error before execution.
# ✓ Use type hints in production code
def calculate_age(birth_year: int) -> int:
from datetime import datetime
return datetime.now().year - birth_year
# ✓ Use isinstance() for polymorphism
def process(obj: object) -> None:
if isinstance(obj, str):
print(obj.upper())
elif isinstance(obj, list):
print(f"List with {len(obj)} items")
# ✓ Document type requirements in docstrings
def fetch_data(url: str, timeout: Optional[float] = None) -> Dict[str, Any]:
"""
Fetch JSON data from URL.
Args:
url: The URL to fetch
timeout: Optional timeout in seconds
Returns:
Parsed JSON data as dictionary
"""
pass
# ✗ Don't mix type checking approaches
def bad_mix(x): # No type hint
if type(x) == int: # Uses type() instead of isinstance()
return x * 2
# ✓ Use Any sparingly
from typing import Any
def flexible_function(data: Any) -> str:
"""When you truly need to accept anything."""
return str(data)| Concept | Remember |
|---|---|
| Type Hints | Use for documentation and static checking with mypy |
| isinstance() | Better than type() for polymorphism and inheritance |
| Try-Except | Essential for safe runtime conversion |
| Union & Optional | Express multiple possible types |
| Protocol | Duck typing with type safety |
Explore Getting User Input for handling user data safely.
Ready to practice? Challenges | Quiz
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward