how to type hint a dictionary with values of different types in python
当将字典声明为文本时,是否有一种方法来键入提示我对特定键期望的值?
然后,讨论一下:有没有关于用Python输入字典的指导原则?我想知道在字典中混合类型是否被认为是不好的做法。
下面是一个例子:
考虑类的
(免责声明:我意识到在这个例子中,一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Rectangle: def __init__(self, corners: Tuple[Tuple[float, float]], **kwargs): self.x, self.z = corners[0][0], corners[0][1] self.elements = { 'front': Line(corners[0], corners[1]), 'left': Line(corners[0], corners[2]), 'right': Line(corners[1], corners[3]), 'rear': Line(corners[3], corners[2]), 'cog': calc_cog(corners), 'area': calc_area(corners), 'pins': None } class Line: def __init__(self, p1: Tuple[float, float], p2: Tuple[float, float]): self.p1, self.p2 = p1, p2 self.vertical = p1[0] == p2[0] self.horizontal = p1[1] == p2[1] |
当我键入以下内容时
1 2 | rec1 = Rectangle(rec1_corners, show=True, name='Nr1') rec1.sides['f... |
Pycharm会为我推荐
1 | rec1.sides['front'].ver... |
Pycharm将建议
所以pycharm会记住类的
如果函数的输出类型被暗示,那么pycharm也会考虑到这一点。
所以假设在上面的
1 | self.pins = None # type: List[Pin] |
(前提是完成了必要的进口)
在字典文字声明中有没有一种方法给出相同的类型提示?
以下内容不符合我的要求:
在文本声明的末尾添加一个
1 2 3 | 'area': calc_area(corners), 'pins': None } # type: Union[Line, Tuple[float, float], float, List[Pin]] |
向每行添加类型提示:
1 2 3 | 'area': calc_area(corners), # type: float 'pins': None # type: List[Pin] } |
这种事情有最佳实践吗?
更多背景:
我和pycharm中的python一起工作,并广泛使用了打字,因为它有助于我在工作中预测和验证我的工作。当我创建新的类时,我有时也会将一些不常用的属性丢到字典中,以避免将对象与太多的属性混淆(这在调试模式中很有用)。
您正在查找typeddit。它目前只是一个mypy唯一的扩展,但有计划在不久的将来使它成为一个正式批准的类型。不过,我不确定Pycharm是否支持这个功能。
所以,在你的情况下,你应该这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from mypy_extensions import TypedDict RectangleElements = TypedDict('RectangleElements', { 'front': Line, 'left': Line, 'right': Line, 'rear': Line, 'cog': float, 'area': float, 'pins': Optional[List[Pin]] }) class Rectangle: def __init__(self, corners: Tuple[Tuple[float, float]], **kwargs): self.x, self.z = corners[0][0], corners[0][1] self.elements = { 'front': Line(corners[0], corners[1]), 'left': Line(corners[0], corners[2]), 'right': Line(corners[1], corners[3]), 'rear': Line(corners[3], corners[2]), 'cog': calc_cog(corners), 'area': calc_area(corners), 'pins': None } # type: RectangleElements |
如果您使用的是python 3.6+,那么您可以使用基于类的语法更优雅地输入这些内容。
不过,在您的具体案例中,我认为大多数人只会将这些数据存储为常规字段而不是听写。不过,我相信您已经考虑过这种方法的优缺点,因此我将不向您讲授它。
经过更多的调查,目前我能找到的最佳解决方法是确保类
因此:
1 2 3 4 | class Pin: def __init__(self, **kwargs): if len(kwargs) == 0: return |
现在,在OP中的示例中,我可以执行以下操作来实现我想要的目标:
1 2 3 4 | ... 'area': calc_area(corners), 'pins': List[Pin(),] } |
但是,如果我有一个基本类型(或类型)作为条目,那么这将不起作用。
1 2 3 4 5 6 | ... 'area': calc_area(corners), 'pins': List[Pin(),] 'color': None 'lap_times': None } |
在哪里?
在这种情况下,最好的解决办法是
1 2 3 4 5 6 7 8 | ... 'area': calc_area(corners), 'pins': List[Pin(),] 'color': 'blue' 'lap_times': [0.,] } self.elements['color'], self.elements['lap_times'] = None, None |
这些看起来都不太优雅,所以我仍然希望有人能提出更好的建议。