python - Python 类元信息中 __init__ 函数的类型提示

标签 python sqlalchemy pycharm type-hinting

我想做的是用它的 DeclarativeMeta 类复制 SQLAlchemy 所做的事情。使用此代码,

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 的输入提示: 整数,

Type-hinting with Python, PyCharm and SQLAlchemy

它在运行时的工作方式是通过 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)

有效,但我没有得到类型提示,

No __init__ type hint

如果我确实传递了参数,我实际上会收到一个Unexpected Argument 警告,

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

最佳答案

从上面的 python 3.7 开始,您可以通过使用 @dataclass 并向实例字段添加适当的类型提示来实现相同的效果。

https://docs.python.org/3/library/dataclasses.html

screenshot of typehint

关于python - Python 类元信息中 __init__ 函数的类型提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49095677/

相关文章:

postgresql - 从 SQLAlchemy 中的查询返回 "computed"列

python - SQLAlchemy/SQLSoup 在 MySQL 中看不到临时表

Python筛选素数

python - 将 sqlalchemy 库添加到 pycharm 中的谷歌应用程序引擎

python - 在 python 中获取行百分比来绘制

javascript - Pycharm:导航到 require ('path/to/file' 中指定的 JS 源)

pycharm - 如何查明我目前在 Pycharm 中所在的类(class)?

python - PyCharm - 一些断点在 Django 项目中不起作用

python - 3.5 : Type Hinting and Method Overloading

python - 如何在OpenGL中绘制垂直于向量的矩形