
Passo 1 de 8
Especificar os elementos de listas e conjuntos
Use tipos parametrizados para declarar o tipo de cada elemento aceito por listas e conjuntos.
Trilha de aprendizado · Nível 12 · Tutorial 2
Expressar os tipos de elementos, chaves e valores de coleções, incluindo estruturas aninhadas, e nomear anotações extensas com aliases.
Especificar os elementos de listas e conjuntos
Use tipos parametrizados para declarar o tipo de cada elemento aceito por listas e conjuntos. 2 min
Separar os tipos de chaves e valores
Anote dicionários especificando, separadamente, o tipo das chaves e o tipo dos valores. 2 min
Distinguir posições fixas e comprimento variável em tuplas
Escolha entre anotações de tuplas com posições definidas e tuplas homogêneas de tamanho variável. 2 min
Declarar o contrato de coleções vazias
Declare o tipo pretendido de listas, conjuntos e dicionários vazios para que o contrato continue claro antes das primeiras inserções. 2 min
Compor anotações para estruturas aninhadas
Combine anotações de coleções para descrever cada nível de uma estrutura e verificar o tipo esperado nas operações internas. 3 min
Armazenar objetos de classes próprias
Use o nome de uma classe para declarar quais instâncias uma coleção pode armazenar e preserve esse contrato em estruturas aninhadas. 2 min
Dar nomes às anotações com aliases
Use aliases para tornar contratos extensos mais legíveis, sem mudar os valores aceitos pela anotação. 2 min
Aplicar e verificar os contratos de uma coleção
Integre anotações de coleções em um script curto, use o mypy para localizar incompatibilidades e corrija o código preservando contratos específicos. 4 min

Passo 1 de 8
Use tipos parametrizados para declarar o tipo de cada elemento aceito por listas e conjuntos.
Em uma anotação como list[int], list identifica o contêiner e int define o tipo de cada elemento que ele deve guardar. Para conjuntos, a mesma ideia aparece em set[str].
Use os tipos embutidos em minúsculas: não é necessário importar List ou Set de typing.
A forma externa mostra a coleção; o tipo entre colchetes descreve seus itens.
![Comparação visual entre uma lista contendo números inteiros com a anotação list[int] e um conjunto contendo palavras com a anotação set[str].](https://cursa-json-routes.s3.amazonaws.com/learning-paths/pt/python/b730454e0225/level-12/tutorial-02/step-01/screen-01/item-02.webp)
list e set descrevem o contêiner; int e str descrevem cada elemento.
Cada valor inicial e cada novo argumento devem ser compatíveis com o tipo entre colchetes.
idades: list[int] = [18, 27, 42]
idades.append(35) # compatível
# idades.append("30") # incompatível para mypy
etiquetas: set[str] = {"novo", "oferta"}
etiquetas.add("online") # compatível
# etiquetas.add(10) # incompatível para mypyDica
idades: list[int] não transforma automaticamente textos em números e não bloqueia uma inserção enquanto o programa roda. O contrato permite que o mypy identifique a incompatibilidade ao analisar o código.
Uma lista que deve conter somente nomes precisa da anotação nomes: list[____] = ["Ana", "Caio"].
Para guardar somente códigos numéricos únicos, escreva codigos: set[____] = {101, 205}.
Considere pontuacoes: list[int] = [10, 20]. Qual inserção viola o contrato?

Passo 2 de 8
Anote dicionários especificando, separadamente, o tipo das chaves e o tipo dos valores.
A anotação de um dicionário tem dois parâmetros: dict[tipo_da_chave, tipo_do_valor].
Em dict[str, int], toda chave deve ser str e todo valor deve ser int. A posição importa: o primeiro tipo descreve o que fica antes dos dois-pontos; o segundo, o que fica depois.
Observe como os lados de cada par correspondem à anotação.

Em cada par chave: valor, a chave atende ao primeiro parâmetro e o valor ao segundo.
Os pares iniciais e as atribuições posteriores precisam respeitar os dois tipos declarados.
pontuacoes: dict[str, int] = {
"Ana": 18,
"Bia": 24,
}
pontuacoes["Caio"] = 31 # chave str, valor int
pontuacoes["Ana"] = 20 # atualiza com outro int
# pontuacoes[7] = 12 # erro: a chave deveria ser str
# pontuacoes["Davi"] = "dez" # erro: o valor deveria ser intDica
A anotação não converte nem bloqueia valores enquanto o programa executa. Ao verificar o arquivo, o mypy pode apontar tanto uma chave incompatível quanto um valor incompatível.
Relacione cada conjunto de pares à anotação de dicionário que o descreve.
Toque em um item e depois no par correspondente.

Passo 3 de 8
Escolha entre anotações de tuplas com posições definidas e tuplas homogêneas de tamanho variável.
Em uma tupla de posições fixas, cada tipo descreve uma posição específica. A anotação tuple[str, int] exige exatamente dois itens: primeiro um str, depois um int.
Assim, ("Ana", 3) atende ao contrato. Já (3, "Ana") troca a ordem, e ("Ana", 3, 8) tem um item a mais.
Compare a tupla de duas posições com uma sequência homogênea repetível.

Em tuple[str, int], posição, tipo e quantidade são definidos. Em tuple[str, ...], o tipo se repete e a quantidade pode variar.
Use tuple[str, ...] quando a tupla puder ter qualquer quantidade de textos — inclusive nenhum. Todos os itens, se existirem, devem ser str.
Não confunda as duas formas:
tuple[str]: exatamente uma posição, do tipo str.tuple[str, ...]: zero ou mais posições, todas do tipo str.par: tuple[str, int] = ("maçãs", 4)
# par = (4, "maçãs") # incompatível: ordem invertida
# par = ("maçãs", 4, 2) # incompatível: três itens
etiqueta: tuple[str] = ("novo",)
# etiqueta = () # incompatível: falta a única posição
rotulos: tuple[str, ...] = ()
rotulos = ("novo", "oferta", "online")
# rotulos = ("novo", 7) # incompatível: 7 não é strUma função recebe códigos de cupom. Pode receber nenhum código, um código ou vários, e todos são textos. Qual é a anotação adequada?
Considere resultado: tuple[str, int]. Qual valor é compatível?

Passo 4 de 8
Declare o tipo pretendido de listas, conjuntos e dicionários vazios para que o contrato continue claro antes das primeiras inserções.
Uma coleção vazia não mostra quais valores ela deverá aceitar no restante do programa. Quando esse contrato importa, escreva uma anotação explícita na criação.
A anotação descreve os valores permitidos no futuro; ela não depende de haver elementos agora.

Mesmo vazias, as coleções podem declarar o tipo de elementos — ou de chaves e valores — que receberão.
Cada variável recebe o contrato que suas operações futuras deverão respeitar.
nomes: list[str] = []
codigos: set[int] = set()
pontos_por_usuario: dict[str, int] = {}Exemplo
tarefas: list[str] = [] começa sem valores, mas já informa que append deve receber textos.
tarefas: list[str] = []
tarefas.append("revisar pedido") # compatível
tarefas.append(3) # incompatível para o mypyA anotação não converte 3 em texto nem bloqueia essa linha durante a execução. Ela permite que o verificador aponte o conflito estático.
Dica
Se você sabe que a coleção guardará textos, inteiros ou pares específicos, declare esse tipo. Trocar o contrato por Any elimina justamente a verificação que ajudaria a detectar uma inserção errada.
Complete a anotação para que a lista aceite nomes, mesmo antes de receber o primeiro nome:
participantes: ____ = []
Digite apenas a anotação da coleção.

Passo 5 de 8
Combine anotações de coleções para descrever cada nível de uma estrutura e verificar o tipo esperado nas operações internas.
Uma coleção aninhada usa uma anotação de coleção dentro de outra. Em dict[str, list[int]], a camada externa é um dicionário: cada chave é str e cada valor é uma list[int].
Ao acessar vendas["segunda"], o resultado deixa de ser o dicionário inteiro: é uma lista de inteiros.
Cada nível de dados corresponde a uma camada da anotação.
![Diagrama de um dicionário cujas chaves de texto apontam para listas contendo números inteiros, conectado visualmente à estrutura de colchetes dict[str, list[int]].](https://cursa-json-routes.s3.amazonaws.com/learning-paths/pt/python/b730454e0225/level-12/tutorial-02/step-05/screen-01/item-02.webp)
A camada externa descreve chaves e valores; a camada interna descreve os elementos de cada lista.
Observe os tipos obtidos em cada acesso.
vendas: dict[str, list[int]] = {
"segunda": [12, 18],
"terca": [9],
}
valores_da_segunda = vendas["segunda"] # list[int]
primeira_venda = vendas["segunda"][0] # int
vendas["terca"].append(15) # correto: a lista interna aceita int
# vendas["terca"].append("15") # mypy aponta incompatibilidade
Exemplo
A chave "terca" é compatível com str, mas isso não torna qualquer valor válido no acesso interno. Como vendas["terca"] é list[int], o argumento de append precisa ser int.
Você também pode colocar uma tupla tipada dentro de uma lista. Em list[tuple[str, int]], cada elemento da lista é uma tupla de exatamente duas posições: primeiro um texto, depois um inteiro.
A anotação acompanha a estrutura real dos dados.
itens: list[tuple[str, int]] = [
("caderno", 3),
("caneta", 10),
]
primeiro_item = itens[0] # tuple[str, int]
nome = itens[0][0] # str
quantidade = itens[0][1] # int
itens.append(("borracha", 5)) # correto
# itens.append(("régua", "5")) # incompatível: a segunda posição deve ser int
Uma agenda guarda, para cada dia em texto, uma lista de horários inteiros: agenda: ___ = {"segunda": [9, 14]}
Considerando agenda: dict[str, list[int]], qual operação é compatível com a anotação?

Passo 6 de 8
Use o nome de uma classe para declarar quais instâncias uma coleção pode armazenar e preserve esse contrato em estruturas aninhadas.
Quando uma lista deve guardar objetos de uma classe, use o nome da classe como o tipo do elemento. Em list[Produto], a coleção aceita instâncias de Produto.
A anotação não representa a classe em si: ela descreve os objetos criados a partir dela que serão armazenados.
Cada bloco interno representa uma instância de Produto; a lista externa é anotada como list[Produto].

O tipo entre colchetes é o tipo de cada elemento da coleção.
A chave externa é um texto, e cada valor é uma lista de instâncias de Produto.
class Produto:
def __init__(self, nome: str, preco: float) -> None:
self.nome = nome
self.preco = preco
def esta_em_promocao(self) -> bool:
return self.preco < 50.0
catalogo: dict[str, list[Produto]] = {
"papelaria": [Produto("Caderno", 32.0)]
}
produto = catalogo["papelaria"][0]
print(produto.nome)
print(produto.esta_em_promocao())Leia a anotação de fora para dentro: catalogo["papelaria"] produz list[Produto]; adicionar [0] produz Produto. Por isso, o verificador conhece nome e esta_em_promocao() nesse ponto.
Já catalogo["papelaria"].append("Caneta") é incompatível: uma string não é uma instância de Produto. A anotação orienta o mypy, mas não bloqueia essa chamada automaticamente durante a execução.
Dica
Com o arquivo salvo, execute python -m mypy nome_do_arquivo.py. Um diagnóstico nessa inserção indica que o valor fornecido não atende ao contrato Produto da lista interna.
Considere a classe e a variável abaixo:
class Produto:
def __init__(self, nome: str) -> None:
self.nome = nome
estoque = [Produto("Caderno"), Produto("Caneta")]Qual anotação declara corretamente o contrato de estoque?

Passo 7 de 8
Use aliases para tornar contratos extensos mais legíveis, sem mudar os valores aceitos pela anotação.
Quando uma anotação aninhada aparece em vários pontos, dê a ela um nome significativo com a instrução type. Em Python 3.12+, um alias para um estoque pode ser declarado assim: type Estoque = dict[str, list[Produto]].
Leia Estoque como uma abreviação do contrato completo: cada chave é str e cada valor é uma lista de instâncias de Produto.

O nome curto substitui a repetição visual, mas preserva todos os níveis da estrutura.
Considere que a classe Produto já foi definida.
class Produto:
def __init__(self, nome: str) -> None:
self.nome = nome
type Estoque = dict[str, list[Produto]]
catalogo: Estoque = {
"frutas": [Produto("maçã")]
}
def adicionar_categoria(estoque: Estoque, categoria: str) -> Estoque:
estoque[categoria] = []
return estoque
O alias pode anotar variáveis, parâmetros e retornos. Ele não cria uma classe chamada Estoque nem um novo tipo nominal: para o mypy, Estoque equivale a dict[str, list[Produto]].
Por isso, o valor atribuído ainda precisa respeitar a estrutura completa.
Complete a linha para nomear a estrutura dict[str, list[Produto]] como Estoque:
_____ Estoque = dict[str, list[Produto]]
Verdadeiro ou falso: depois de declarar type Estoque = dict[str, list[Produto]], Python converte automaticamente textos inseridos nas listas em objetos Produto.

Passo 8 de 8
Integre anotações de coleções em um script curto, use o mypy para localizar incompatibilidades e corrija o código preservando contratos específicos.
Neste programa, o dicionário externo associa uma categoria a uma lista de objetos Produto. Além dele, haverá um conjunto de textos e dois formatos de tupla: um resumo com posições fixas e etiquetas de tamanho variável.
Ao investigar um diagnóstico, percorra a anotação de fora para dentro: descubra qual operação está sendo feita e qual é o tipo exigido exatamente naquele nível.
A imagem conecta cada parte do programa ao seu contrato estático.

Em dict[str, list[Produto]], a chave é str, o valor é uma list e cada elemento dessa lista deve ser um Produto.
Crie um arquivo chamado inventario.py no seu editor e copie o código completo abaixo. As três linhas marcadas com ERRO INTENCIONAL violam contratos diferentes: uma inserção em conjunto, uma atualização do dicionário aninhado e um retorno de tupla.
O alias usa a instrução type, disponível no Python 3.12 ou superior.
from dataclasses import dataclass
@dataclass
class Produto:
nome: str
preco_centavos: int
type Estoque = dict[str, list[Produto]]
type Resumo = tuple[str, int]
def adicionar(estoque: Estoque, categoria: str, produto: Produto) -> None:
estoque.setdefault(categoria, []).append(produto)
def resumir(estoque: Estoque) -> Resumo:
total = sum(
produto.preco_centavos
for produtos in estoque.values()
for produto in produtos
)
return ("total", str(total)) # ERRO INTENCIONAL
estoque: Estoque = {}
categorias: set[str] = set()
etiquetas: tuple[str, ...] = ("novo", "disponivel")
adicionar(estoque, "livros", Produto("Python prático", 5990))
categorias.add("livros")
categorias.add(99) # ERRO INTENCIONAL
estoque["ofertas"] = ["brinde"] # ERRO INTENCIONAL
print(resumir(estoque))
print(etiquetas)No terminal, na pasta do arquivo, execute o comando abaixo. Corrija somente os valores ou a implementação: não use Any e não altere os aliases para tipos mais amplos.
Para cada erro, compare o tipo encontrado com o tipo exigido pela operação:
set[str].add(...) exige um str.Estoque deve ser uma list[Produto].Resumo exige exatamente str na primeira posição e int na segunda.python -m mypy --strict --python-version 3.12 inventario.pyDepois de ajustar o arquivo e executar o comando novamente, relate: qual tipo era esperado em cada um dos três locais, qual valor incompatível foi encontrado e qual foi o resultado da nova verificação.
Escreva pelo menos 120 caracteres (0/120).
Exemplo
categorias.add("ofertas")
estoque["ofertas"] = [Produto("Marcador", 300)]
return ("total", total)A primeira correção respeita set[str]; a segunda respeita o valor list[Produto] de Estoque; a terceira respeita as duas posições de Resumo.
Resumo
Use este roteiro ao escrever ou revisar coleções tipadas:
dict[str, list[Produto]].type para dar um nome reutilizável a uma estrutura extensa; ele não cria uma nova classe.Any.Parabéns! Você concluiu: Anotar coleções e estruturas aninhadas
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks