Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a recursive Python type defined over several aliases?

I want this logical type structure:

from typing import List, Dict, Union

ObjectType = Dict[str, 'EntryType']
ListType = List['EntryType']
EntryType = Union[str, 'ListType', 'ObjectType']

mypy reports these errors:

mdl/structure.py:7: error: Cannot resolve name "ObjectType" (possible cyclic definition)
mdl/structure.py:7: error: Cannot resolve name "EntryType" (possible cyclic definition)
mdl/structure.py:8: error: Cannot resolve name "ListType" (possible cyclic definition)
...

Is there some way to encode this recursive data type?

I believe I can inline the individual types, typing out the full definition each time, to allow recursion. I'd prefer to avoid this, as it's bulky, and less clear.

like image 441
edA-qa mort-ora-y Avatar asked Oct 14 '19 12:10

edA-qa mort-ora-y


Video Answer


2 Answers

Recursive types are not yet supported in mypy. They're definitely on the roadmap though, although I'm not exactly sure when the implementation work will begin. It was slated to begin earlier this year, but the prerequisite refactor of the semantic analysis phase (which made a lot of the internal changes needed to cleanly support recursive types) ended up taking longer than expected, so I'm not sure what the new timeline is. Maybe sometime in the next half-year or so?

A possible alternative approach you could look into is to use TypedDicts, which let you assign specific types to certain keys. This is particularly useful if you already know ahead of time what the structure of your input dicts will be -- if you know exactly what keys your ObjectTypes will have, and precisely what they'll map to. Libraries like pydantic are also helpful here, if you prefer working with objects over dicts and prefer not to have to write a bunch of validation logic.

Pragmatically though, if your dict structure is genuinely free-form, it might be best to just go with ObjectType = Dict[str, object]. After all, in order to identify exactly which EntryType you're dealing with, you're going to have to add in a few isinstance checks anyways to appropriate narrow the type. So, while starting off with object instead of Union[str, ListType, ObjectType] will be mildly annoying, it might not be too huge of an imposition depending on what you're doing.

like image 50
Michael0x2a Avatar answered Sep 21 '22 13:09

Michael0x2a


mypy does not support recursive types: https://github.com/python/mypy/issues/731

Your type definition is not possible for mypy, and not with any other type checker I know either. Inlining the individual types will give you infinitely long type definitions, as it's recursive.

like image 44
Markus Unterwaditzer Avatar answered Sep 18 '22 13:09

Markus Unterwaditzer