Intrastellar Explorer
Intrastellar Explorer

Reputation: 2381

Python get keys from unbound TypedDict

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

Upvotes: 16

Views: 11228

Answers (4)

Waleed Khan
Waleed Khan

Reputation: 11467

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.

Upvotes: 2

Eugene Butan
Eugene Butan

Reputation: 51

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}

Upvotes: 5

Omar Omeiri
Omar Omeiri

Reputation: 1825

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'])

Upvotes: 1

Amitai Irron
Amitai Irron

Reputation: 2055

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'>}

Upvotes: 21

Related Questions