Movatterモバイル変換


[0]ホーム

URL:


ContentsMenuExpandLight modeDark modeAuto light/dark, in light modeAuto light/dark, in dark modeSkip to content
mypy 1.19.1 documentation
Logo
mypy 1.19.1 documentation

First steps

Type system reference

Configuring and running mypy

Miscellaneous

Project Links

Back to top

TypedDict

Python programs often use dictionaries with string keys to represent objects.TypedDict lets you give precise types for dictionaries that representobjects with a fixed schema, such as{'id':1,'items':['x']}.

Here is a typical example:

movie={'name':'Blade Runner','year':1982}

Only a fixed set of string keys is expected ('name' and'year' above), and each key has an independent value type (strfor'name' andint for'year' above). We’ve previouslyseen thedict[K,V] type, which lets you declare uniformdictionary types, where every value has the same type, and arbitrary keysare supported. This is clearly not a good fit formovie above. Instead, you can use aTypedDict to give a precisetype for objects likemovie, where the type of eachdictionary value depends on the key:

fromtypingimportTypedDictMovie=TypedDict('Movie',{'name':str,'year':int})movie:Movie={'name':'Blade Runner','year':1982}

Movie is aTypedDict type with two items:'name' (with typestr)and'year' (with typeint). Note that we used an explicit typeannotation for themovie variable. This type annotation isimportant – without it, mypy will try to infer a regular, uniformdict type formovie, which is not what we want here.

Note

If you pass aTypedDict object as an argument to a function, notype annotation is usually necessary since mypy can infer thedesired type based on the declared argument type. Also, if anassignment target has been previously defined, and it has aTypedDict type, mypy will treat the assigned value as aTypedDict,notdict.

Now mypy will recognize these as valid:

name=movie['name']# Okay; type of name is stryear=movie['year']# Okay; type of year is int

Mypy will detect an invalid key as an error:

director=movie['director']# Error: 'director' is not a valid key

Mypy will also reject a runtime-computed expression as a key, asit can’t verify that it’s a valid key. You can only use stringliterals asTypedDict keys.

TheTypedDict type object can also act as a constructor. Itreturns a normaldict object at runtime – aTypedDict doesnot define a new runtime type:

toy_story=Movie(name='Toy Story',year=1995)

This is equivalent to just constructing a dictionary directly using{...} ordict(key=value,...). The constructor form issometimes convenient, since it can be used without a type annotation,and it also makes the type of the object explicit.

Like all types,TypedDicts can be used as components to buildarbitrarily complex types. For example, you can define nestedTypedDicts and containers withTypedDict items.Unlike most other types, mypy uses structural compatibility checking(or structural subtyping) withTypedDicts. ATypedDict object withextra items is compatible with (a subtype of) a narrowerTypedDict, assuming item types are compatible (totality also affectssubtyping, as discussed below).

ATypedDict object is not a subtype of the regulardict[...]type (and vice versa), sincedict allows arbitrary keys to beadded and removed, unlikeTypedDict. However, anyTypedDict object isa subtype of (that is, compatible with)Mapping[str,object], sinceMapping only provides read-only access to the dictionary items:

defprint_typed_dict(obj:Mapping[str,object])->None:forkey,valueinobj.items():print(f'{key}:{value}')print_typed_dict(Movie(name='Toy Story',year=1995))# OK

Note

Unless you are on Python 3.8 or newer (whereTypedDict is available instandard librarytyping module) you need to installtyping_extensionsusing pip to useTypedDict:

python3 -m pip install --upgrade typing-extensions

Totality

By default mypy ensures that aTypedDict object has all the specifiedkeys. This will be flagged as an error:

# Error: 'year' missingtoy_story:Movie={'name':'Toy Story'}

Sometimes you want to allow keys to be left out when creating aTypedDict object. You can provide thetotal=False argument toTypedDict(...) to achieve this:

GuiOptions=TypedDict('GuiOptions',{'language':str,'color':str},total=False)options:GuiOptions={}# Okayoptions['language']='en'

You may need to useget() to access items of a partial (non-total)TypedDict, since indexing using[] could fail at runtime.However, mypy still lets use[] with a partialTypedDict – youjust need to be careful with it, as it could result in aKeyError.Requiringget() everywhere would be too cumbersome. (Note that youare free to useget() with totalTypedDicts as well.)

Keys that aren’t required are shown with a? in error messages:

# Revealed type is "TypedDict('GuiOptions', {'language'?: builtins.str,#                                            'color'?: builtins.str})"reveal_type(options)

Totality also affects structural compatibility. You can’t use a partialTypedDict when a total one is expected. Also, a totalTypedDict is notvalid when a partial one is expected.

Supported operations

TypedDict objects support a subset of dictionary operations and methods.You must use string literals as keys when calling most of the methods,as otherwise mypy won’t be able to check that the key is valid. Listof supported operations:

Note

clear() andpopitem() are not supported since they are unsafe– they could delete requiredTypedDict items that are not visible tomypy because of structural subtyping.

Class-based syntax

An alternative, class-based syntax to define aTypedDict is supportedin Python 3.6 and later:

fromtypingimportTypedDict# "from typing_extensions" in Python 3.7 and earlierclassMovie(TypedDict):name:stryear:int

The above definition is equivalent to the originalMoviedefinition. It doesn’t actually define a real class. This syntax alsosupports a form of inheritance – subclasses can define additionalitems. However, this is primarily a notational shortcut. Since mypyuses structural compatibility withTypedDicts, inheritance is notrequired for compatibility. Here is an example of inheritance:

classMovie(TypedDict):name:stryear:intclassBookBasedMovie(Movie):based_on:str

NowBookBasedMovie has keysname,year andbased_on.

Mixing required and non-required items

In addition to allowing reuse acrossTypedDict types, inheritance also allowsyou to mix required and non-required (usingtotal=False) itemsin a singleTypedDict. Example:

classMovieBase(TypedDict):name:stryear:intclassMovie(MovieBase,total=False):based_on:str

NowMovie has required keysname andyear, whilebased_oncan be left out when constructing an object. ATypedDict with a mix of requiredand non-required keys, such asMovie above, will only be compatible withanotherTypedDict if all required keys in the otherTypedDict are required keys in thefirstTypedDict, and all non-required keys of the otherTypedDict are also non-required keysin the firstTypedDict.

Read-only items

You can usetyping.ReadOnly, introduced in Python 3.13, ortyping_extensions.ReadOnly to mark TypedDict items as read-only (PEP 705):

fromtypingimportTypedDict# Or "from typing ..." on Python 3.13+fromtyping_extensionsimportReadOnlyclassMovie(TypedDict):name:ReadOnly[str]num_watched:intm:Movie={"name":"Jaws","num_watched":1}m["name"]="The Godfather"# Error: "name" is read-onlym["num_watched"]+=1# OK

A TypedDict with a mutable item can be assigned to a TypedDictwith a corresponding read-only item, and the type of the item canvarycovariantly:

classEntry(TypedDict):name:ReadOnly[str|None]year:ReadOnly[int]classMovie(TypedDict):name:stryear:intdefprocess_entry(i:Entry)->None:...m:Movie={"name":"Jaws","year":1975}process_entry(m)# OK

Unions of TypedDicts

Since TypedDicts are really just regular dicts at runtime, it is not possible touseisinstance checks to distinguish between different variants of a Union ofTypedDict in the same way you can with regular objects.

Instead, you can use thetagged union pattern. The referencedsection of the docs has a full description with an example, but in short, you willneed to give each TypedDict the same key where each value has a uniqueLiteral type. Then, check that key to distinguishbetween your TypedDicts.

Inline TypedDict types

Note

This is an experimental (non-standard) feature. Use--enable-incomplete-feature=InlineTypedDict to enable.

Sometimes you may want to define a complex nested JSON schema, or annotatea one-off function that returns a TypedDict. In such cases it may be convenientto use inline TypedDict syntax. For example:

deftest_values()->{"width":int,"description":str}:return{"width":42,"description":"test"}classResponse(TypedDict):status:intmsg:str# Using inline syntax here avoids defining two additional TypedDicts.content:{"items":list[{"key":str,"value":str}]}

Inline TypedDicts can also by used as targets of type aliases, but due toambiguity with a regular variables it is only allowed for (newer) explicittype alias forms:

fromtypingimportTypeAliasX={"a":int,"b":int}# creates a variable with type dict[str, type[int]]Y:TypeAlias={"a":int,"b":int}# creates a type aliastypeZ={"a":int,"b":int}# same as above (Python 3.12+ only)

Also, due to incompatibility with runtime type-checking it is strongly recommendedtonot use inline syntax in union types.

On this page

[8]ページ先頭

©2009-2025 Movatter.jp