Python get keys from unbound TypedDict
Asked Answered
A

4

15

I would like to get the keys from an unbound TypedDict subclass.

What is the correct way to do so?

Below I have a hacky method, and I'm wondering if there's a more standard way.


Current Method

I used inspect.getmembers on the TypedDict subclass, and saw the __annotations__ attribute houses a mapping of the keys + type annotations. From there, I use .keys() to get access to all of the keys.

from typing_extensions import TypedDict


class SomeTypedDict(TypedDict):

    key1: str
    key2: int


print(SomeTypedDict.__annotations__.keys())

Prints: dict_keys(['key1', 'key2'])

This does work, but I am wondering, is there a better/more standard way?


Versions

python==3.6.5
typing-extensions==3.7.4.2
Atmospherics answered 21/5, 2020 at 20:44 Comment(0)
T
18

The code documentation explicitly states (referring to a sample derived class Point2D):

The type info can be accessed via the Point2D.__annotations__ dict, and the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.

So if the modules code says this, there is no reason to look for another method.

Note that your method only printed the names of the dictionary keys. You can get the names and the type simply by accessing the full dictionary:

print(SomeTypedDict.__annotations__)

Which will get you back all the info:

{'key1': <class 'str'>, 'key2': <class 'int'>}
Tomasatomasina answered 21/5, 2020 at 22:4 Comment(3)
Point2D.__required_keys__ and Point2D.__optional_keys__ don't seem to be available in 3.8. Were they removed for some reason?Naidanaiditch
It was added in 3.9: github.com/python/cpython/blob/3.9/Lib/typing.py#L1973-L1974 In 3.8, no such thing: github.com/python/cpython/blob/3.8/Lib/typing.py#L1712-L1757Agley
Best practice changed in Python 3.10, and now it's recommended to use inspect.get_annotations() if possible. I posted this answer.Memento
C
2

You can use get_type_hints function.

from typing import TypedDict, get_type_hints


class StackParams(TypedDict):
    UnsignedAuthorizerName: str
    UnsignedAuthorizerStatus: bool
    TableName: str
    SignedAuthorizerName: str
    SignedAuthorizerStatus: bool
    SignedAuthorizerTokenKeyName: str


get_type_hints(StackParams)
# {'UnsignedAuthorizerName': str, 'UnsignedAuthorizerStatus': bool, 'TableName': str, 'SignedAuthorizerName': str, 'SignedAuthorizerStatus': bool, 'SignedAuthorizerTokenKeyName': str}

Contact answered 21/6, 2023 at 23:7 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Naranjo
M
2

For Python 3.10 and newer, it's best to use inspect.get_annotations. See Annotations Best Practices:

Python 3.10 adds a new function to the standard library: inspect.get_annotations(). In Python versions 3.10 and newer, calling this function is the best practice for accessing the annotations dict of any object that supports annotations. This function can also “un-stringize” stringized annotations for you.

The document also discusses how to support earlier versions of Python.

Memento answered 23/4 at 2:1 Comment(0)
W
1

You can also declare a static method like this:

from typing import TypedDict

class StockPrice(TypedDict):
    symbol: str
    year: int
    month: int
    day: int
    o: int
    h: int
    l: int
    c: int
    v: int | None

    @staticmethod# type: ignore
    def keys():
        return StockPrice.__dict__['__annotations__'].keys()
    
StockPrice.keys() 
#dict_keys(['symbol', 'year', 'month', 'day', 'o', 'h', 'l', 'c', 'v'])
Whiteman answered 13/2, 2023 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.