如何将运行时对象类型用作泛型类型提示参数?

时间:2016-02-08 00:27:02

标签: python python-3.5 type-hinting

简介

使用Python / MyPy类型提示,可以使用.pyi存根将注释保存在单独的文件中以实现。我正在使用此功能来提供SQLAlchemy的ORM(更具体地说,flask_sqlalchemy插件)的基本提示。

模型定义如下:

class MyModel(db.Model):
    id = db.Column()
    ...
...

其中db.Model直接包含在SQLAlchemy中。 例如,可以通过以下方式查询它们:

MyModel.query.filter({options: options}).one_or_none()

其中filter()会返回另一个Query,而one_or_none()会返回MyModel(或显式为None的实例。

下面的.pyi文件成功提示上面的构造,虽然它不完整 - 没有办法提示one_or_none()的返回类型。

class _SQLAlchemy(sqlalchemy.orm.session.Session):
    class Model:
       query = ... # type: _Query

class _Query(sqlalchemy.orm.query.Query):
    def filter(self, *args) -> query.Query: ...
    def one_or_none(self) -> Any: ...

db = ... # type: _SQLAlchemy

问题

如何完全和一般地暗示上述内容,并提示one_or_none()的返回类型? 我的第一次尝试是使用泛型,但看起来我无法访问相关的子类型(在给定的示例中,MyModel)。为了说明一种非工作方法:

from typing import Generic, TypeVar

_T = TypeVar('_T')

class _SQLAlchemy(sqlalchemy.orm.session.Session):
    class Model:
       def __init__(self, *args, **kwargs):
           self.query = ... # type: _Query[self.__class__]

class _Query(Generic[_T], sqlalchemy.orm.query.Query):
    def filter(self, *args) -> _Query[_T]: ...
    def one_or_none(self) -> _T: ...

db = ... # type: _SQLAlchemy

有没有办法让这个工作?

为具体和例子道歉,但我试着用一个通用的例子简明扼要地写这个,但它从来没有像目前那样清晰(可能仍然不多!)

修改

另一种非工作方法(我知道这将限制必须调用myModelInstance.query ...而不是静态MyModel.query,但即使这不起作用):

from typing import Generic, TypeVar

_T = TypeVar('_T')

class _SQLAlchemy(sqlalchemy.orm.session.Session):
    class Model:

       @property
       def query(self: _T) -> _Query[_T]: ...

class _Query(Generic[_T], sqlalchemy.orm.query.Query):
    def filter(self, *args) -> _Query[_T]: ...
    def one_or_none(self) -> _T: ...

db = ... # type: _SQLAlchemy

1 个答案:

答案 0 :(得分:1)

幸运的是,现在可以为该特定问题https://github.com/dropbox/sqlalchemy-stubs

使用类型注释存根。

此处提供了Query类型注释的确切实现:https://github.com/dropbox/sqlalchemy-stubs/blob/master/sqlalchemy-stubs/orm/query.pyiarchive