2017-01-01 2 views
2

Каков правильный способ аннотировать аргумент функции, который ожидает объект класса вместо экземпляра этого класса?Как аннотировать экземпляры типов (вместо экземпляров класса)?

В приведенном ниже примере, some_class аргумент, как ожидается, будет экземпляр типа (которым является классом), но проблема в том, что type слишком широк:

def construct(some_class: type, related_data:Dict[str, Any]) -> Any: 
    ... 

В случае, когда some_class ожидает определенный набор типов объектов, используя type, совсем не помогает. Модуль typing может быть нуждается в классе общего, что делает это:

def construct(some_class: Class[Union[Foo, Bar, Baz]], related_data:Dict[str, Any]) -> Union[Foo, Bar, Baz]: 
    ... 

В приведенном выше примере, some_class является Foo, Bar или Faz класс, не экземпляр этого. Не должно иметь значения их позиции в дереве классов, потому что some_class: Class[Foo] также должен быть действительным. Поэтому

# classes are callable, so it is OK 
inst = some_class(**related_data) 

или

# instances does not have __name__ 
clsname = some_class.__name__ 

или

# an operation that only Foo, Bar and Baz can perform. 
some_class.a_common_classmethod() 

должно быть ОК mypy, pytype, PyCharm и т.д.

Как это может быть сделано с текущей реализации (Python 3.6 или ранее)?

+0

Если вам нужно быть более конкретным, чем 'type', введите метакласс или абстрактный базовый класс. – jonrsharpe

+0

@jonrsharpe - Я думаю, что метакласс будет делать трюк, но я еще не достиг такого уровня в Python. С введением переменных аннотаций в 3.6 (в том числе «ClassVar', чтобы отличать переменные экземпляра от переменных класса), мне интересно, почему я должен использовать' type' для аннотирования объектов класса, когда существует так много способов аннотировать экземпляры класса. Может быть, мне придется ждать будущего обновления или рецепта :). –

+0

Кажется, мне придется полагаться на 'typing.Type' и делать что-то вроде' Foo = TypeVar ['Foo', bond = Bar] ', где' Bar' является ABC, затем, взяв пример выше: ' def construct (some_class: Type [Foo], ...) -> Foo'. Мне особенно не нравится использовать 'TypeVar', но, похоже, это единственный способ ... –

ответ

2

Чтобы комментировать объект, являющийся классом, используйте typing.Type. Например, это было бы сказать, что тип проверки some_class является класс Foo или любого из его подклассов:

from typing import Type 
class Foo: ... 
class Bar(Foo): ... 
class Baz: ... 
some_class: Type[Foo] 
some_class = Foo # ok 
some_class = Bar # ok 
some_class = Baz # error 
some_class = Foo() # error 

Обратите внимание, что Type[Union[Foo, Bar, Baz]] и Union[Type[Foo], Type[Bar], Type[Baz]] полностью эквивалентны.

Если some_class может быть любым из нескольких классов, вы можете сделать их все наследуемыми от того же базового класса и использовать Type[BaseClass]. Обратите внимание, что наследование должно быть не виртуальным на данный момент (поддержка mypy для виртуального наследования - being discussed).

Отредактировано для подтверждения того, что Type[Union[... разрешено.

Смежные вопросы