如何键入提示具有不同类型值的字典 [英] How to type hint a dictionary with values of different types

查看:132
本文介绍了如何键入提示具有不同类型值的字典的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将字典声明为文字时,是否有一种方法可以提示我特定键的值?

When declaring a dictionary as a literal, is there a way to type-hint what value I am expecting for a specific key?

然后进行讨论:是否有关于Python中字典键入的指导原则?我想知道在字典中混合类型是否被认为是不好的做法.

And then, for discussion: are there guiding principles around dictionary typing in Python? I'm wondering whether it is considered bad practice to mix types in dictionaries.

这是一个例子:

考虑在类的__init__中声明字典:

Consider the declaration of a dictionary in a class's __init__ :

(免责声明:我在示例中意识到,某些.elements条目可能更适合作为类属性,但这只是为了示例).

(disclaimer: I realize in the example, some of the .elements entries would probably be more appropriate as class attributes, but it's for the sake of the example).

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'.更好的是,当我这样做

Pycharm will suggest 'front' for me. Better still, when I do

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

Pycharm会建议.vertical

Pycharm will suggest .vertical

因此Pycharm会记住类__init__中字典文字声明中的键,以及它们的值的预期类型.或者更确切地说:它期望任何值都具有文字声明中的任何一种类型-可能与我执行self.elements = {} # type: Union[type1, type2]会执行的操作相同.无论哪种方式,我都觉得它很有帮助.

So Pycharm remembers the keys from the dictionary literal declaration in the class's __init__, and also their values' expected types. Or rather: it expects any value to have any one of the types that are in the literal declaration - probably the same as if I had done a self.elements = {} # type: Union[type1, type2] would do. Either way, I find it super helpful.

如果您的函数具有输出类型提示,则Pycharm也会考虑到这一点.

If your functions have their outputs type-hinted, the Pycharm will also take that into account.

因此,假设在上面的Rectangle示例中,我想指出pinsPin对象的列表...如果pins是普通的类属性,则应该是

So assuming that in the Rectangle example above, I wanted to indicate that pins is a list of Pin objects... if pins was a normal class attribute, it would be

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

(前提是已完成必要的导入)

(provided the necessary imports were done)

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

Is there a way to give the same type hint in the dictionary literal declaration?

以下内容没有不能达到我想要的目的:

The following does not achieve what I am looking for:

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

Add a Union[...] type hint at the end of the literal declaration?

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

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

Adding a type-hint to every line:

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

这种事情是否有最佳实践?

Is there a best practice for this kind of thing?

更多背景:

我在PyCharm中使用Python,并且广泛使用了打字,因为它可以帮助我在进行过程中预测和验证我的工作.在创建新类时,有时还会将一些不常用的属性放入字典中,以避免过多的属性使对象混乱(这在调试模式下很有用).

I work with Python in PyCharm and I make extensive use of typing, since it helps me to predict and validate my work as I go along. When I create new classes, I also sometimes throw some less frequently used properties into a dictionary to avoid cluttering the object with too many attributes (this is helpful in debug mode).

推荐答案

您正在寻找使其成为官方认可的类型 a>在不久的将来.不过,我不确定PyCharm是否支持此功能.

You are looking for TypedDict. It is currently only a mypy-only extension, but there are plans to make it an officially sanctioned type in the near-future. I am not sure if PyCharm supports this feature yet, though.

因此,您可以这样做:

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+,则可以使用基于类的语法.

If you are using Python 3.6+, you can type this all more elegantly using the class-based syntax.

不过,在您的特定情况下,我认为大多数人只会将这些数据片段存储为常规字段,而不是字典.我确定您已经考虑了这种方法的利弊,所以我将不为您讲解.

In your specific case though, I think most people would just store those pieces of data as regular fields instead of a dict. I'm sure you've already thought through the pros and cons of that approach though, so I'll skip lecturing you about it.

这篇关于如何键入提示具有不同类型值的字典的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆