Откуда рекомендуется импортировать Callable в Python 3.10
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Откуда рекомендуется импортировать Callable в Python 3.10?
Краткий ответ
В Python 3.10 рекомендуется импортировать Callable из модуля collections.abc (абстрактные базовые классы), а не из typing. Это изменение произошло из-за эволюции типизации в Python и её переориентации на стандартные классы.
История изменений
Python < 3.9
В ранних версиях Python Callable импортировали только из typing:
from typing import Callable
def process(callback: Callable[[int], str]) -> None:
pass
Это было единственным способом, так как в collections.abc не было универсального Callable для аннотирования.
Python 3.9
В Python 3.9 появилась возможность импортировать Callable из collections.abc, но typing.Callable ещё работал.
Python 3.10+
Рекомендуемый подход — импортировать из collections.abc:
from collections.abc import Callable
def process(callback: Callable[[int], str]) -> None:
result = callback(42)
print(result)
process(lambda x: f"Number: {x}")
Почему именно collections.abc?
1. Унификация типизации
Python переходит на использование стандартных классов вместо специальных типов из typing. Это делает код более прозрачным:
# Старый подход (typing)
from typing import Callable, List, Dict
def old_function(callback: Callable, items: List[str]) -> Dict[str, int]:
pass
# Новый подход (встроенные типы + collections.abc)
from collections.abc import Callable
def new_function(callback: Callable, items: list[str]) -> dict[str, int]:
pass
2. Согласованность с другими абстрактными типами
Другие абстрактные типы уже находятся в collections.abc:
from collections.abc import (
Callable, # Для функций
Iterator, # Для итераторов
Sequence, # Для последовательностей
Mapping, # Для словарей
Set # Для множеств
)
def handler(func: Callable[[str], int], items: Sequence[str]) -> Mapping[str, int]:
return {item: func(item) for item in items}
3. Производительность
collections.abc.Callable — это «нативный» класс, который работает быстрее, чем специальный тип из typing.
Полный пример
from collections.abc import Callable, Iterator
from typing import TypeVar
T = TypeVar("T")
class EventEmitter:
def __init__(self):
self._handlers: dict[str, list[Callable]] = {}
def on(self, event: str, callback: Callable[[any], None]) -> None:
if event not in self._handlers:
self._handlers[event] = []
self._handlers[event].append(callback)
def emit(self, event: str, *args) -> None:
if event in self._handlers:
for handler in self._handlers[event]:
handler(*args)
# Использование
emitter = EventEmitter()
emitter.on("click", lambda x: print(f"Clicked: {x}"))
emitter.emit("click", "button")
Когда ещё используется typing.Callable?
В редких случаях, когда нужны продвинутые функции типизации из typing:
from typing import Callable, overload, TypeVar
T = TypeVar("T")
@overload
def apply(func: Callable[[int], int], value: int) -> int: ...
@overload
def apply(func: Callable[[str], str], value: str) -> str: ...
def apply(func, value):
return func(value)
Однако даже здесь сам Callable лучше импортировать из collections.abc.
Практические рекомендации
- Всегда используйте
from collections.abc import Callableв Python 3.10+ - Используйте встроенные типы
list,dictвместоList,Dictизtyping - Включите
from __future__ import annotationsдля совместимости - Обновляйте линтер (mypy, pylint) до последних версий
Это делает код более читаемым, производительным и соответствует современным стандартам Python.