How to type hint a dictionary with values of different types

霸气de小男生 提交于 2019-12-05 08:08:29

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.

So, in your case, you'd do:

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

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.

After some more investigation, the best workaround I could find so far was to ensure the the class Pin could return some kind of a placeholder, and then use the placeholder as a value in the literal declaration.

therefore:

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

Now, in the example in the OP, I could do the following to achieve what I wanted:

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

However, if I had a basic type (or types) as a entries, this would not work.

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

where color expects a string and lap_times expects a list with floats...

In such a case the best work-around would be

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

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

Neither of these seems very elegant, so I am still hoping someone can suggest something better.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!