pycharm 如何键入不同类型值的字典提示

isr3a4wc  于 2022-11-08  发布在  PyCharm
关注(0)|答案(3)|浏览(170)

当把字典声明为文字时,有没有一种方法可以提示我对特定键期望什么值?
然后,进行讨论:在Python中有关于字典类型的指导原则吗?我想知道在字典中混合类型是否被认为是不好的做法。
下面是一个例子:
考虑一个类的__init__中的字典声明:

  • (免责声明:我意识到在这个例子中,一些.elements条目可能更适合作为类属性,但这是为了这个例子。)*
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]

当我键入以下内容时,

rec1 = Rectangle(rec1_corners, show=True, name='Nr1')
rec1.sides['f...

Pycharm会为我建议'front'。更好的是,当我这样做的时候

rec1.sides['front'].ver...

Pycharm会建议.vertical
所以Pycharm记住了类的__init__中字典文字声明的键,以及它们的值的预期类型。它期望任何值都具有文本声明中的任何一种类型--可能就像我做了一个self.elements = {} # type: Union[type1, type2]一样。
如果你的函数有它们的输出类型提示,那么Pycharm也会考虑到这一点。
因此,假设在上面的Rectangle示例中,我想指出pinsPin对象的列表......如果pins是一个普通类属性,它将是:

self.pins = None  # type: List[Pin]

(前提是已完成必要的导入)
有没有办法在字典文字声明中给予相同的类型提示?
以下内容无法实现我的期望:
是否在文本声明的末尾添加Union[...]类型提示?

'area': calc_area(corners),
            'pins': None
        }  # type: Union[Line, Tuple[float, float], float, List[Pin]]

在每一行中添加类型提示:

'area': calc_area(corners),  # type: float
            'pins': None  # type: List[Pin]
        }

对于这种事情有什么最好的做法吗?
更多背景信息:
我在PyCharm中使用Python,并且我广泛使用类型化,因为它帮助我预测和验证我的工作。当我创建新的类时,我有时也会把一些不常用的属性放入字典中,以避免过多的属性使对象变得混乱(这在调试模式中很有帮助)。

jjhzyzn0

jjhzyzn01#

你正在寻找TypedDict。它目前只是一个mypy专用的扩展,但是在不久的将来有计划扩展到make it an officially sanctioned type。我不确定PyCharm是否支持这个特性。
所以,在你的情况下,你会做:

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+,你可以使用基于类的语法更优雅地输入。
不过,在您的具体情况下,我想大多数人会将这些数据片段存储为常规字段,而不是dicture。我相信您已经考虑过这种方法的利弊,所以我就不对您进行说教了。

7uzetpgm

7uzetpgm2#

最简单的方法:

from typing import TypedDict

class Movie(TypedDict):
   name: str
   year: int

movie: Movie = {'name': 'Blade Runner', 'year': 1982}

movie['year'] = '1982' # Error: invalid value type ("int" expected)

打字字典-PEP 589

rsl1atfo

rsl1atfo3#

经过更多的研究,到目前为止我能找到的最好的解决方法是确保类Pin可以返回某种占位符,然后在文本声明中使用占位符作为值。
因此:

class Pin:
    def __init__(self,**kwargs):
        if len(kwargs) == 0:
            return

现在,在OP中的示例中,我可以执行以下操作来实现我想要的:

...
        'area': calc_area(corners),
        'pins': List[Pin(),]
    }

然而,如果我有一个基本类型(或类型)作为条目,这将不起作用。

...
        'area': calc_area(corners),
        'pins': List[Pin(),]
        'color': None
        'lap_times': None
    }

其中color需要一个字符串,lap_times需要一个带有浮点数的列表...
在这种情况下,最好的解决方法是

...
        'area': calc_area(corners),
        'pins': List[Pin(),]
        'color': 'blue'
        'lap_times': [0.,]
    }

    self.elements['color'], self.elements['lap_times'] = None, None

这两个似乎都不是很优雅,所以我仍然希望有人能建议更好的东西。

相关问题