如何在python中键入提示具有不同类型值的字典

lev*_*eer 6 python dictionary typing type-hinting pycharm

在将字典声明为文字时,有没有办法输入提示我期望特定键的值?

然后,讨论:在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]
Run Code Online (Sandbox Code Playgroud)

当我键入以下类型

rec1 = Rectangle(rec1_corners, show=True, name='Nr1')
rec1.sides['f...
Run Code Online (Sandbox Code Playgroud)

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

rec1.sides['front'].ver...
Run Code Online (Sandbox Code Playgroud)

Pycharm会建议 .vertical

因此,Pycharm会记住类中字典文字声明中的键__init__,以及它们的值的预期类型.或者更确切地说:它期望任何值都具有文字声明中的任何一种类型 - 可能与我做过的self.elements = {} # type: Union[type1, type2]一样.无论哪种方式,我发现它非常有用.

如果你的函数的输出类型为暗示,那么Pycharm也会将其考虑在内.

所以假设在Rectangle上面的例子中,我想表明这pins是一个Pin对象列表......如果pins是一个普通的类属性,那就是

    self.pins = None  # type: List[Pin]
Run Code Online (Sandbox Code Playgroud)

(如果已完成必要的进口)

有没有办法在字典文字声明中提供相同的类型提示?

以下内容无法满足我的需求:

Union[...]在文字声明的末尾添加类型提示?

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

为每一行添加一个类型提示:

            'area': calc_area(corners),  # type: float
            'pins': None  # type: List[Pin]
        }
Run Code Online (Sandbox Code Playgroud)

这种事情有最好的做法吗?

更多背景:

我在pycharm中使用python并且我大量使用了打字,因为它帮助我预测和验证我的工作.当我创建新类时,我有时也会将一些不太常用的属性抛出到字典中,以避免使用太多属性来混淆对象(这在调试模式下很有用).

Arm*_*her 10

最简单的方法:

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)
Run Code Online (Sandbox Code Playgroud)

TypedDict-PEP 589


Mic*_*x2a 6

您正在寻找TypedDict.它目前只是一个仅限mypy的扩展,但有计划在不久的将来使其成为官方认可的类型.不过,我不确定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
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Python 3.6+,则可以使用基于类的语法更优雅地输入.

在您的具体情况下,我认为大多数人只会将这些数据存储为常规字段而不是字典.我相信你已经考虑过这种方法的优点和缺点了,所以我会跳过讲授你的话.

  • [typing.TypeDict](https://docs.python.org/3/library/typing.html#typing.TypedDict)使用Python 3.8进入标准库 (6认同)