【发布时间】:2018-08-12 05:39:21
【问题描述】:
我想做的是复制SQLAlchemy 所做的事情,以及它的DeclarativeMeta 类。有了这段代码,
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
当你在PyCharm、Person(... 中创建一个人时,你会得到关于id: int, name: str, age: int 的输入提示,
它在运行时的工作方式是通过 SQLAlchemy 的 _declarative_constructor 函数,
def _declarative_constructor(self, **kwargs):
cls_ = type(self)
for k in kwargs:
if not hasattr(cls_, k):
raise TypeError(
"%r is an invalid keyword argument for %s" %
(k, cls_.__name__))
setattr(self, k, kwargs[k])
_declarative_constructor.__name__ = '__init__'
为了得到真的很好的类型提示(如果你的类有一个 id 字段,Column(Integer) 你的构造函数类型提示为id: int),PyCharm 实际上是在做一些底层魔法,特定于 SQLAlchemy,但我不需要它那么好/好,我只想能够从类的元信息中以编程方式添加类型提示。
所以,简而言之,如果我有类似的课程,
class Simple:
id: int = 0
name: str = ''
age: int = 0
我希望能够像上面那样初始化类Simple(id=1, name='asdf'),但同时也能获得类型提示。我可以得到一半(功能),但不是类型提示。
如果我像 SQLAlchemy 那样进行设置,
class SimpleMeta(type):
def __init__(cls, classname, bases, dict_):
type.__init__(cls, classname, bases, dict_)
metaclass = SimpleMeta(
'Meta', (object,), dict(__init__=_declarative_constructor))
class Simple(metaclass):
id: int = 0
name: str = ''
age: int = 0
print('cls', typing.get_type_hints(Simple))
print('init before', typing.get_type_hints(Simple.__init__))
Simple.__init__.__annotations__.update(Simple.__annotations__)
print('init after ', typing.get_type_hints(Simple.__init__))
s = Simple(id=1, name='asdf')
print(s.id, s.name)
它工作,但我没有得到任何类型提示,
如果我确实传递了参数,我实际上会收到 Unexpected Argument 警告,
在代码中,我手动更新了__annotations__,这使得get_type_hints 返回正确的东西,
cls {'id': <class 'int'>, 'name': <class 'str'>, 'age': <class 'int'>}
init before {}
init after {'id': <class 'int'>, 'name': <class 'str'>, 'age': <class 'int'>}
1 asdf
【问题讨论】:
-
考虑使用在 Py3.7 标准库中引入的
dataclasses,可作为包或attrs库用于 Py3.6。命名元组也很有用。 -
不幸的是,Pycharm 目前对 sqlalchemy 和 pydantic 等其他库没有很好的支持(至少在自动完成和类型提示方面)。尽管它确实对内置库(如前面提到的数据类)提供了很好的支持。
标签: python sqlalchemy pycharm type-hinting