← Назад к вопросам

Чем заменили Union в Python 3.10?

1.0 Junior🔥 251 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Синтаксис 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.