Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Синтаксис Union типов в Python 3.10+
В Python 3.10 введена одна из самых ожидаемых фишек — новый синтаксис для объединения типов через оператор pipe (|). Это кардинально улучшило читаемость кода при работе с типами.
Что было раньше: Union из typing
До Python 3.10 для обозначения нескольких возможных типов приходилось использовать Union из модуля typing:
from typing import Union
def process_data(value: Union[int, str, float]) -> Union[str, None]:
"""Принимает int, str или float, возвращает str или None"""
if isinstance(value, int):
return f"Число: {value}"
elif isinstance(value, str):
return value.upper()
elif isinstance(value, float):
return f"Дробное: {value}"
return None
Проблемы:
- Многословно:
Union[int, str, float]занимает много места - Медленнее читается: нужно привыкнуть к синтаксису
- Требует импорта: обязательно
from typing import Union
Новый синтаксис в Python 3.10+: pipe operator
Теперь вместо Union[A, B, C] можно писать A | B | C:
def process_data(value: int | str | float) -> str | None:
"""Принимает int, str или float, возвращает str или None"""
if isinstance(value, int):
return f"Число: {value}"
elif isinstance(value, str):
return value.upper()
elif isinstance(value, float):
return f"Дробное: {value}"
return None
# Использование
result1: str | None = process_data(42) # ✓ OK
result2: str | None = process_data("hello") # ✓ OK
result3: str | None = process_data(3.14) # ✓ OK
Pipe operator с None (Optional)
Для типов, которые могут быть None, раньше использовался Optional[T] (что равносильно Union[T, None]):
from typing import Optional
# Старый способ
def get_user(user_id: int) -> Optional[str]:
...
# Новый способ (Python 3.10+)
def get_user(user_id: int) -> str | None:
...
Использование в контейнерах и сложных типах
Оператор | работает везде, где используются типы:
from typing import List, Dict, Callable
# Списки разных типов
values: list[int | str | float] = [1, "text", 3.14, 2]
# Словари с union типами
data: dict[str, int | str | bool] = {
"count": 42,
"name": "John",
"active": True
}
# Функции, которые возвращают разные типы
callback: Callable[[int], str | int] = lambda x: x * 2 if x % 2 == 0 else str(x)
Generic типы с union
При работе с generics синтаксис также стал чище:
from typing import TypeVar, Generic
T = TypeVar(T)
# Раньше (использование Union сложнее читалось)
from typing import Union
def handle(value: Union[T, None]) -> Union[T, str]:
...
# Теперь (более естественно)
def handle(value: T | None) -> T | str:
...
Объединение пользовательских типов
Оператор | работает не только со встроенными типами, но и с классами:
class User:
def __init__(self, name: str):
self.name = name
class Admin(User):
def __init__(self, name: str, level: int):
super().__init__(name)
self.level = level
class Guest:
def __init__(self, session_id: str):
self.session_id = session_id
# Функция принимает разные типы пользователей
def process_account(account: User | Admin | Guest) -> str:
if isinstance(account, Admin):
return f"Admin {account.name} level {account.level}"
elif isinstance(account, User):
return f"User {account.name}"
else: # Guest
return f"Guest session {account.session_id}"
Совместимость с type hints инструментами
Все инструменты типизации поддерживают новый синтаксис:
# mypy, pylint, pyright понимают оба варианта
def old_style(x: Union[int, str]) -> None:
...
def new_style(x: int | str) -> None:
...
Когда использовать каждый вариант
# Python 3.10+ (предпочтительно)
def modern_function(value: int | str | None) -> bool:
return isinstance(value, (int, str))
# Python 3.9 и ниже (нужно использовать Union)
from typing import Union
def legacy_function(value: Union[int, str, None]) -> bool:
return isinstance(value, (int, str))
Практическое применение в production
from dataclasses import dataclass
from datetime import datetime
@dataclass
class ApiResponse:
status_code: int
data: dict | list | None = None
error: str | None = None
timestamp: datetime = None
def is_success(self) -> bool:
return 200 <= self.status_code < 300
# Использование
response: ApiResponse = ApiResponse(
status_code=200,
data={"users": ["Alice", "Bob"]},
timestamp=datetime.now()
)
Вывод
Новый синтаксис A | B | C полностью заменил Union[A, B, C], начиная с Python 3.10. Это:
- Компактнее и читабельнее
- Меньше импортов (не нужен
typing.Union) - Более интуитивно — похоже на математическую нотацию
- Стандарт де-факто — все новые проекты используют этот синтаксис
Если проект поддерживает Python 3.10+, всегда используйте | вместо Union. Это не просто удобнее, но и соответствует современным best practices.