【问题标题】:Is it possible to statically type a generic C[T] as T in Python?是否可以在 Python 中将通用 C[T] 静态类型为 T ?
【发布时间】:2021-06-09 14:42:15
【问题描述】:

我正在使用 SQLite,其中类型提示仍然远非完美,我最终得到了一个我认为我想做的 MCVE,它可能与静态类型的 ABC 相关。

例子:

T = TypeVar('T')


class ColumnarValue(Generic[T]):
    pass


def test1(guard: ColumnarValue[str]): ...
def test2(guard: ColumnarValue[int]): ...

# These should work
test1("Hello")
test2(42)

# These should be type errors
test1(42)
test2("Hello")

# Or, likewise:
test_assignment_1: ColumnarValue[str] = "this line should typecheck"
test_assignment_2: ColumnarValue[int] = "this line should NOT typecheck"

我尝试使用 ABC,但由于它们似乎使用 ABC.register() 进行注册,因此类型检查器不知道我在说什么。

我也尝试过通用协议,但我必须设计一个协议来保护每种类型 T 所期望的功能。

我正在使用 Pyright/Pylance 对此进行测试,但如果这是问题的一部分,则可以考虑替代方案。

我还发现了https://github.com/antonagestam/phantom-types,根据文档,“不会增加任何处理或内存开销”。这并不完全正确,因为它们在运行时通过 .parse 和 __instancecheck__ 协议(虽然它们在技术上不会创建任何新对象,但它们确实在堆栈帧中有一些开销)。

唉,这不是一个静态检查器,虽然那里的解决方案似乎使用assert isinstance("hello", MyStr) 来确保类型检查器可以在该行之后满足此类保证(这至少在 mypy 和 pylance 中有效),但它不会使用assert isinstance("hello", MyInt) 触发任何类型检查时错误。代码会在运行时使断言失败。

最终,我希望能够拥有一个 T 类型,我可以将其称为 C[T],这样当我在模型中声明 col_name = Column(String, ...) 时,我就可以 col_name = "value" 或它的一些变体这是静态检查的。

这可能吗,如果是,魔法在哪里?

【问题讨论】:

    标签: python mypy python-typing pylance pyright


    【解决方案1】:

    如果您最终要将这些列放入模型类中,您可以使用 descriptors(例如 property 装饰器在后台使用的,如果您熟悉的话)。

    粗略的草图:

    from typing import TypeVar, Generic, Any
    
    T = TypeVar("T")
    
    
    class ColumnarValue(Generic[T]):
        def __get__(self, instance: object, owner: Any) -> T:
            ...
    
        def __set__(self, instance: object, value: T) -> None:
            ...
    
    
    class Model:
        some_str_column: ColumnarValue[str]
        some_int_column: ColumnarValue[int]
    
    
    m = Model()
    m.some_str_column = "this line typechecks"
    m.some_int_column = "this line does NOT typecheck"
    

    还可以看看 sqlalchemy 如何处理所有这些here。 特别是 Mapped 类,其实际类型定义为 here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      • 2020-03-13
      • 2017-12-27
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多