Home > Net >  Representing different types for dictionaries based on their keys
Representing different types for dictionaries based on their keys

Time:03-13

I want to create a type that represents this dictionary

{
   "13fc71ee-e676-4e5d-a561-a20af5bcbaaf": "123",
   "8d742ecf-6ae9-4408-a5a0-b1110f9b5365": "fdsafdsa",
   "literal": {
       "any": "dict",
   },
}

This is the closest type I can come up with:

Dict[UUID | Literal["literal"], str | dict]

The main issue with the above type signature is that the following dictionary would be allowed:

{
   "8d742ecf-6ae9-4408-a5a0-b1110f9b5365": {
       "dictionary": 321,
   },
   "literal": "some string",
}

Is there a way to annotate a dictionary with a type that can either be a UUID key for a string value or a string literal for a dict value?

CodePudding user response:

What you're asking for potentially requires runtime knowledge and thus cannot be encoded (in a useful way) as a type. Perhaps there is a way to create a custom type that can work with static type checkers for some similar types, but I imagine it would be complicated. Thus, I propose some alternatives:

typing.TypedDict:
class ItemType(TypedDict):
    uuids: dict[str, str]
    literal: dict[str, Any]

d: ItemType = {
    "uuids": {
        "13fc71ee-e676-4e5d-a561-a20af5bcbaaf": "123",
        "8d742ecf-6ae9-4408-a5a0-b1110f9b5365": "fdsafdsa",
    },
    "literal": {
        "any": "dict",
    },
}
Dataclasses:
@dataclass
class Item:
    uuids: dict[str, str]
    literal: dict[str, Any]

d = Item(**{
    "uuids": {
        "13fc71ee-e676-4e5d-a561-a20af5bcbaaf": "123",
        "8d742ecf-6ae9-4408-a5a0-b1110f9b5365": "fdsafdsa",
    },
    "literal": {
        "any": "dict",
    },
})

Optionally, one can consider overriding __getitem__ to allow dictionary-like access d["literal"].

Runtime checks

If all else fails, and you really need to verify constraints that the type system cannot handle, you can do various runtime checks via isinstance or perhaps via libraries like beartype.

  • Related