问题描述
我正在使用 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,...)
时,我可以{{ 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,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"