2016-04-12 2 views
4

У меня есть функция в python, которая возвращает класс вместо экземпляра. Как указать, что возвращаемое значение является подклассом определенного типа?Проверка типа возвращаемого класса PEP 484

В следующем примере я установить возвращаемое значение как тип, но я хотел бы также указать, что тип имеет все атрибуты BaseClass:

from typing import Dict, Any 

def class_constructor(name: str, attrs: Dict[str, Any]) -> type 
    ConstructedClass = type(name, (BaseClass,), attrs) 
    return ConstructedClass 

class BaseClass: ... 

Я не могу сказать (...) -> BaseClass, поскольку это указывает на экземпляр BaseClass, а не на BaseClass.

Чтобы ответить на мой вопрос, это выглядит как python/typing issue #107. На данный момент, лучшим решением является:

from typing import Dict, Any 

class BaseClass: ... 

def class_constructor(name: str, attrs: Dict[str, Any]) -> Callable[Any, BaseClass] 
    ConstructedClass = type(name, (BaseClass,), attrs) 
    return ConstructedClass 

Если вы знаете __init__ подпись, вы можете использовать, что вместо Any в Callable[Any, ...].

Когда поддержка Type[T] добавляют раствор будет:

from typing import Dict, Any 

class BaseClass: ... 

def class_constructor(name: str, attrs: Dict[str, Any]) -> Type[BaseClass] 
    ConstructedClass = type(name, (BaseClass,), attrs) 
    return ConstructedClass 
+0

Можете ли вы представить конкретный, управляемый пример, который не может делать то, что вы хотите? – chepner

+0

Добавлена ​​поддержка 'Type [T]', как в mypy, так и в PEP 484. – max

ответ

0

Я думаю, вам нужно будет создать новый класс, используемый BaseClass исключительно как способ мечения его и любых классов потомка.

class BaseClassMeta(type): 
    pass 

class BaseClass(metaclass=BaseClassMeta): 
    ... 

def class_constructor(name: str, attrs: Dict[str, Any]) -> BaseClassMeta 
    ConstructedClass = BaseClassMeta(name, (BaseClass,), attrs) 
    return ConstructedClass 
+0

Полученный класс действительно функционирует должным образом, но это не решает проблему. 'BaseClassMeta (...)' создает тип, но 'ConstructedClass (...)' создает объект, поэтому возвращаемый тип не может быть 'BaseClassMeta'. Я могу немного приблизиться к тому, что мне нужно, используя '-> Callable [[...], BaseClass]' где '...' - это аргументы функции '__init__' (которые должны совместно использовать общий интерфейс для всех построенных классы для того, чтобы этот код был вообще разумным). По крайней мере PyCharm может вывести атрибуты объекта ConstructedClass (...) ', если не атрибуты возвращаемого класса. – Neapolitan

+0

Почему бы и нет? Где вы на самом деле создаете экземпляр 'ConstructedClass'? Оба «BaseClass» и «ConstructedClass» являются экземплярами «BaseClassMeta». – chepner

+0

Возвращаемое значение из конструктора классов действительно является экземпляром 'BaseClassMeta', но оно ведет себя по-разному. То есть 'BaseClassMeta (...) -> type', но' ConstructedClass (...) -> object'. Если вы скажете, что 'class_constructor' возвращает' BaseClassMeta', тогда статический анализ использования 'MyClass = class_constructor (...)' не удастся, если вы позже скажете 'obj = MyClass()', поскольку 'MyClass' типа' BaseClassMeta' 'ожидает ту же подпись, что и функция' type'. – Neapolitan

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