Ваш пример очень динамичен по своей природе. Поскольку основной целью аннотаций типов Python является поддержка статического анализа, их возможности здесь ограничены. Однако я думаю, что мы можем добиться большего успеха, чем Any
!
(Примечание: во избежание путаницы я буду ссылаться на переменную в вашем фрагменте с именем object
как на my_object
, когда я использую object
, я имею в виду тип Python).
Поскольку вы упомянули, что значения в предоставленном словаре должны быть типами, которые могут быть инициированы, разумной аннотацией типа будет либо Dict[str, Type[object]]
, либо Dict[str, Type]
, где последний эквивалентен Dict[str, Type[Any]]
. Первый является наиболее строгим и ограничивает то, что средство проверки типов позволит вам делать с вашей переменной my_object
. Второй лишь немного лучше обычного Any
, хотя он предупреждает вызывающего, когда он случайно предоставляет экземпляр вместо типа.
Из предоставленного вами фрагмента единственный способ использования значения словаря - создать новый экземпляр. Тип — не единственное, что может это сделать. На самом деле, любой вызываемый объект (простая функция, метод класса), который принимает нулевые аргументы и возвращает объект, также будет достаточен. Таким образом, использование Callable[[], object]
предоставит больше гибкости вызывающей стороне функции, а также предупредит, когда передается тип, который не имеет конструктора с нулевым аргументом. Я бы предпочел это Type
, так как это кажется более безопасным и более в духе утиного набора Python.
Что-то лучше, чем простой объект?
Оба решения имеют ограничение, заключающееся в том, что внутри вашей функции мы ничего не знаем о типе my_object
. В общем случае мы «вынуждены» делать isinstance
проверок каждый раз, когда выполняем операцию, не поддерживаемую типом объекта. Но, возможно, в вашем случае использования один словарь не должен содержать любой тип. Это может быть так:
- Все типы имеют общий базовый класс, скажем,
MyBase
.
- Предполагается, что все типы поддерживают общий набор операций (методов или атрибутов).
В случае (1) мы можем заменить тип object
на тип MyBase
. Средство проверки типов должно быть в состоянии убедиться, что операции, поддерживаемые MyBase
, безопасны для использования, и предупреждать, когда предоставленный словарь содержит другие типы.
В случае (2) нам может помочь typing.Protocol
. Вы можете определить собственный протокол с требуемыми операциями и добавить его в аннотацию типа:
class MyCustomProto(Protocol):
foo: int
def bar(self) -> str: ...
Теперь средство проверки типов должно знать, что my_object
должен иметь целочисленный атрибут foo
и метод bar
, возвращающий строку. Обратите внимание, что Protocol
было добавлено в Python 3.8 и доступно для предыдущих версий через typing-extensions пакет.
Диктовка против набора текста. Отображение
Не имеет прямого отношения к вашему вопросу, но если вы используете словарь только для чтения, вам следует рассмотреть возможность замены Dict
на тип Mapping
. Это позволяет вызывающей стороне предоставить любой тип сопоставления, кроме подклассов dict (на практике это маловероятно). Но что еще более важно, он предупреждает вас о случайном изменении предоставленного сопоставления, что может привести к трудностям в поиске ошибок. Таким образом, мое последнее предложение будет Mapping[str, Callable[[], <X>]
, а <X>
будет одним из object
, MyCustomProto
или MyBase
.
person
schot
schedule
23.02.2020
Dict[str, Callable[[], object]]
, либоDict[str, Type[object]]
. - person Michael0x2a   schedule 23.02.2020__init__
, а не на сопоставлении типов, содержащем несколько разных типов. - person schot   schedule 26.02.2020