我正在尝试让 pycharm 的自动完成功能与 python 中的动态类型提示一起使用。假设我们有一个描述符,它在
__init__
上采用“类型”参数并将值转换为 __set__
上的该类型:
import typing as t
_type = t.TypeVar('_type')
class CastDescriptor:
def __init__(self, type: t.Type[_type]):
self.type = type
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, _) -> _type | 'CastDescriptor':
if obj is None:
return self
return obj.__dict__[self.name]
def __set__(self, obj, value):
obj.__dict__[self.name] = self.type(value)
class Test:
a = CastDescriptor(dict)
def __init__(self, a):
self.a = a
test = Test(a=[(1, 2)])
print(test.a) # prints {1:2}
上面的代码工作得很好,但是 pycharm 无法识别属性
test.a
是一个字典,所以自动完成不适用于该属性。
到目前为止我发现的唯一工作方式是显式复制类型
class Test:
a: dict[int, int] = CastDescriptor(dict)
def __init__(self, a):
self.a = a
test = Test(a=[(1, 2)])
test.a.strip() # will be highlited as dict has no attribute 'strip'
不确定是否可行,但如何向 pycharm 显示作为参数传递给描述符的最终属性类型?
这里我将演示:
TypeVars 与普通变量的作用域不同。这意味着即使您在
__init__
和 __get__
中使用相同的,根据 Pycharm 类型检查器,它们也不被认为是相关的。将 Generic 添加到描述符定义将解决此问题。
class CastDescriptor(t.Generic[_type]):
这可以通过在pycharm中执行以下操作来确认。
class Test:
a = CastDescriptor(dict)
b = CastDescriptor(int)
a.__get__(). # Pycharm autocomplete gives options for dict
b.__get__(). # Pycharm autocomplete gives options for int
这更接近所需的行为,但
test.a
仍未被识别为 dict
我这样测试:
test.a = [(1, 2)]
test.a. # Pycharm autocomplete gives options for list
test.a = {1, 2}
test.a. # Pycharm autocomplete gives options for set
即使使用 OP 的显式类型提示解决方案,也可以看到相同的行为。我们有理由相信类型检查器会忽略描述符。
使用Python3.10、Pycharm 2022.3确认的例子