Having the following TypedDict:
class MySubClass(TypedDict):
name: str
color: str
class MyClass(TypedDict):
x: MySubClass
y: str
What is the function, that can extract the keys recursively like this:
[x_name, x_color, y]
The function should be dynamic so that it can extract all kinds of nested structures, but one level of nesting is already enough.
Many Thanks!
Python
>=3.10For Python
>=3.10we have thetyping.is_typeddictfunction that we can use to check, if something is in fact aTypedDictsubtype.We can use
typing.get_type_hints(Python>=3.9) on aTypedDictclass to get the keys and corresponding types defined on it. (This is likely better that using its__annotations__dictionary directly as pointed out by @chepner in a comment.)A simple recursive function to get the keys the way you wanted might look like this:
Demo:
Output:
['a', 'b_x_name', 'b_x_color', 'b_y']Obviously, you might run into name collisions with the way the nested keys are formed. But I am sure you are aware of that.
Side note: If you are on Python
>=3.11and have some keys that are annotated withNotRequired, this solution should still work becauseget_type_hintsresolves those annotations to the underlying type.E.g. the following
Bazclass:The function would still work and return the same output.
Python
3.9Here we need to get creative because
is_typeddictis not available to us. To shamelessly steal bits from Pydantic, we could simply check if something is 1) adictsubtype and 2) has the typicalTypedDictclass attributes. This is obviously less reliable, but should work well enough in most cases:Same Demo, same output.
Python
3.8Without
typing.get_type_hints, we can just use replace that call in theget_typed_dict_keysfunction withcls.__annotations__.Also, the
TypedDict.__required_keys__class attribute was only added in Python3.9, so to see if something is aTypedDict, we can only check for__total__. This is obviously even less robust, but the best we can do with Python3.8.With type annotations etc. adjusted properly, the
3.8code would look like this:Same Demo, same output.
PS, just for fun
Here is a function that can return a nested dictionary of annotations of nested
TypedDicts and optionally flatten it, just because:Demo:
Output: