When working with type hints in Python, we often use Dict
, Any
, and Optional
from the typing
module to specify types more clearly. Here’s how they work.
Dict (Dictionary Type Hint)
The Dict[key_type, value_type]
syntax is used to define a dictionary where you specify the types of keys and values. In Python, type hints are only for static type checking and do not enforce type restrictions at runtime. This means that even though Dict[str, int]
specifies that keys should be strings and values should be integers, Python will not raise a TypeError
if an incompatible dictionary is passed.
If you want to manually enforce type checking, you need to validate types inside the function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| from typing import Dict, Any
def process_data(data: Dict[str, int]) -> None:
for key, value in data.items():
if not isinstance(key, str):
raise TypeError(f"Invalid key type: {type(key)}. Expected str.")
if not isinstance(value, int):
raise TypeError(f"Invalid value type: {type(value)}. Expected int.")
print(f"{key}: {value}")
sample_data = {"apple": 3, "banana": 5}
process_data(sample_data) # Works fine
invalid_data = {1: "three"}
process_data(invalid_data) # TypeError: Invalid key type: <class 'int'>. Expected str.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| apple: 3
banana: 5
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[34], line 15
12 process_data(sample_data) # Works fine
14 invalid_data = {1: "three"}
---> 15 process_data(invalid_data) # Now raises TypeError
Cell In[34], line 6, in process_data(data)
4 for key, value in data.items():
5 if not isinstance(key, str):
----> 6 raise TypeError(f"Invalid key type: {type(key)}. Expected str.")
7 if not isinstance(value, int):
8 raise TypeError(f"Invalid value type: {type(value)}. Expected int.")
TypeError: Invalid key type: <class 'int'>. Expected str.
|
Any (Allow Any Type)
The Any
type allows any kind of value, meaning it can be of any type.
1
2
3
4
5
6
7
8
| from typing import Any
def print_value(value: Any) -> None:
print(f"Value: {value}, Type:{type(value)}")
print_value(123) # Integer
print_value("hello") # String
print_value([1, 2, 3]) # List
|
1
2
3
| Value: 123, Type:<class 'int'>
Value: hello, Type:<class 'str'>
Value: [1, 2, 3], Type:<class 'list'>
|
Optional (Value Can Be None)
Optional[type]
means the value can be either the given type or None
.
It is equivalent to Union[type, None]
.
1
2
3
4
5
6
7
8
9
10
| from typing import Optional
def greet(name: Optional[str] = None) -> str:
if name is None:
return "Hello, Guest!"
return f"Hello, {name}!"
print(greet()) # Hello, Guest! (when `None` is passed)
print(greet("John")) # Hello, John!
|
1
2
| Hello, Guest!
Hello, John!
|
Summary
Type Hint | Description |
---|
Dict[K, V] | A dictionary with key type K and value type V |
Any | Allows any data type |
Optional[T] | Allows either T or None |
You can combine Dict
, Any
, and Optional
to create more flexible function signatures.
1
2
3
4
5
6
7
8
9
10
11
12
| from typing import Dict, Any, Optional
def get_config(settings: Dict[str, Any], key: str) -> Optional[Any]:
return settings.get(key)
config = {"debug": True, "timeout": 30, "api_key": None}
print(get_config(config, "debug")) # True
print(get_config(config, "timeout")) # 30
print(get_config(config, "api_key")) # None
print(get_config(config, "unknown")) # None
|
1
2
3
4
| True
30
None
None
|