As pointed out by Blckknght, you and Stanislav Ivanov in the comments, you can use NamedTuple:
from typing import NamedTuple
class NameInfo(NamedTuple):
name: str
first_letter: str
def get_info(name: str) -> NameInfo:
return NameInfo(name=name, first_letter=name[0])
Starting from Python 3.8 you can use TypedDict which is more similar to what you want:
from typing import TypedDict
class NameInfo(TypedDict):
name: str
first_letter: str
def get_info(name: str) -> NameInfo:
return {'name': name, 'first_letter': name[0]}
As pointed out by Blckknght, you and Stanislav Ivanov in the comments, you can use NamedTuple:
from typing import NamedTuple
class NameInfo(NamedTuple):
name: str
first_letter: str
def get_info(name: str) -> NameInfo:
return NameInfo(name=name, first_letter=name[0])
Starting from Python 3.8 you can use TypedDict which is more similar to what you want:
from typing import TypedDict
class NameInfo(TypedDict):
name: str
first_letter: str
def get_info(name: str) -> NameInfo:
return {'name': name, 'first_letter': name[0]}
TypedDict can also be created using a typename and a dictionary where the keys are the keys and the values are the type of the values, respectively, of the dict to be returned by get_info(). This allows you to create keys that uses characters not in A-Za-z0-9_.
from typing import TypedDict
NameInfo = TypedDict('NameInfo', {'name': str, 'first-letter': str})
def get_info(name: str) -> NameInfo:
return {'name': name, 'first-letter': name[0]}
x = get_info('cottontail')
print(x['first-letter']) # c
Then on PyCharm, the key hint is there (also works on jupyter notebook too by pressing tab).

As a side note, if you want to see the keys of NameInfo, you can do so by assigning the returned value of a get_info call to a variable and subscript that variable. Then, most editors will show the valid keys like in the image above.
Bear in mind that type hinting is not enforced at runtime, so even if get_info is annotated to return a dict with keys (name and first_letter), nothing stops you to have it return something completely different. If get_info must return those 2 keys, you'll have to use a validator like pydantic (which is a third-party package that must be installed, e.g. pip install pydantic). A basic example is as follows. Note that this does not return a dictionary but a pydantic model (as such is not subscriptable) and will complain if any keys are missing or if the types are not what they are supposed to be etc.
from pydantic import BaseModel
class NameInfo(BaseModel):
name: str
first_letter: str
def get_info(name: str) -> NameInfo:
return NameInfo(name=name, first_letter=name[0])
x = get_info('cottontail')
x.first_letter # 'c'
x.name # 'cottontail'
Then on for example, VSCode, the hint is there:

Videos
Basically as the title says. I have a dict representing the str of a variable name and the variable itself. However, I can’t find anything saying how to type hint this. Any help would be greatly appreciated.
Hi folks I tried to keep the title as short and concise as possible, I often find myself struggling for hours in order to properly type annotate nested dictionaries in my code.
If the dict only has 1 level, it works well but with a tiny more complex ones like the following, I have a lot of trouble:
{"@context": "http://schema.org",
"@type": "VideoObject",
"url": "https://www.example.com/0000/adventures-music-videos.html",
"name": "sample movie",
"description": "example",
"thumbnailUrl": "thumbnail.com/1.jpg",
"uploadDate": "2023-11-29",
"duration": "PT2H20M20S",
"contentUrl": "sample_link",
"isAccessibleForFree": false,
"productionCompany": {"@type": "Organization",
"name": "Example",
"@id": "https://www.example.com/0000/studio/music-movies.html"},
"hasPart": [{"@type": "Clip",
"name": "scene 1",
"startOffset": 15,
"endOffset": 2126,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false},
{"@type": "Clip",
"name": "scene 2",
"startOffset": 2128,
"endOffset": 4114,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false},
{"@type": "Clip",
"name": "scene 3",
"startOffset": 4117,
"endOffset": 6055,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false},
{"@type": "Clip",
"name": "scene 4",
"startOffset": 6057,
"endOffset": 8414,
"url": "https://www.example.com/0000/adventures-music-videos.html#scene_0000",
"isAccessibleForFree": false}]}I tried dict[str, object] and I also tried a looong annotation with all the possible types separated by a pipe, but for now the only one that does not trigger mypy in strict mode is dict[str, Any].
Any clues as to what I might be doing wrong?
First, some context. I'm modeling a directory structure, and I'm thinking about how to represent a directory with either a class, a dictionary, or a named tuple. All I want to store is a name, a path, a list of files in the directory, and a list of subdirectories. If I go the class route, any function using my directory class will be annotated with the name of the class (no problems there).
def some_function(dir: Directory) -> None:
passIf I go the named tuple route, my directory class would look like this:
File = NamedTuple('File', [('name', str), ('path', str)])
field_list = [('name', str),
('path', str),
('files', Optional[List[File]]),
('subdirs', Optional[List['Directory']])]
Directory = NamedTuple('Directory', field_list)The function definition for the named tuple version of the model would look exactly the same as for a class. I run into a problem when I want to think about this as a dictionary with type annotations. Obviously there isn't a problem making a dictionary with the same keys and values as in my named tuple, but I have no idea how to write the type annotations for a dictionary structured like that. All of the dictionary type annotations I've seen have a single type for the keys, and a single type for the values e.g. Dict[str, int]. So, how do I write type annotations for a dictionary where the values of my key-value pairs can be of different types?