Suppose I have a function which takes a dictionary as a parameter:
def f(d: dict) -> None:
x = d["x"]
print(x)
Can I specify that this dictionary must have the key "x"
to mypy? I'm looking for something similar to interface from typescript, without changing d
to a class.
The reason I don't want to change d
to a class, is because I am modifying a large existing codebase to add mypy
type checking and this dictionary is used in many places. I would have to modify a lot of code if I had to change all instances of d["x"]
to d.x
.
As of Python 3.8 you can use typing.TypedDict
, added as per PEP 589. For older Python versions you can use the typing-extensions
package
Note that the PEP does acknowledge that the better option is that you use dataclasses for this use-case, however:
Dataclasses are a more recent alternative to solve this use case, but there is still a lot of existing code that was written before dataclasses became available, especially in large existing codebases where type hinting and checking has proven to be helpful.
So the better answer is to consider a different data structure, such as a named tuple or a dataclass, where you can specify the attribute a type has. This is what the typescript declaration does, really:
The
printLabel
function has a single parameter that requires that the object passed in has a property calledlabel
of type string.
Python attributes are the moral equivalent of Typescript object properties. That Typescript object notation and Python dictionaries have a lot in common perhaps confuses matters, but you should not look upon Typescript object declarations as anything but classes, when trying to map concepts to Python.
That could look like this:
from dataclasses import dataclass
@dataclass
class SomeClass:
x: str
def f(sc: SomeClass) -> None:
x = sc.x
print(x)
That said, you can use typing.TypedDict
here:
from typing import TypedDict
class SomeDict(TypedDict):
x: str
def f(d: SomeDict) -> None:
x = d['x']
print(x)
Keys in a TypeDict
declaration are either all required, or all optional (when you set total=False
on the declaration); you'd have to use inheritance to produce a type with some keys optional, see the documentation linked. Note that TypedDict
currently has issues with a mix of optional and required keys; you may want to use the typing-extensions
package to get the Python 3.9 version (which fixes this) as a backport even when using Python 3.8. Just use from typing_extensions import TypedDict
instead of the above from typing ...
import, the typing-extensions
package falls back to the standard library version when appropriate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With