Trilha de aprendizado · Nível 12 · Tutorial 3

Tratar valores opcionais e uniões de tipos

Representar valores que admitem tipos alternativos e organizar condições para que cada operação seja aplicada somente aos tipos compatíveis.

  • Nível: Intermediário
  • Duração: 18 min
  • 8 passos
Tratar valores opcionais e uniões de tipos

O que você vai percorrer

  1. Representar tipos alternativos com | Use o operador | para declarar contratos que aceitam tipos alternativos e reconheça quando uma operação ainda não é segura. 2 min
  2. Separar aceitar None de permitir omissão Diferencie o valor None de um argumento ausente e escreva assinaturas coerentes com cada contrato. 2 min
  3. Distinguir união de elementos e união de coleções Use a posição de | e dos colchetes para expressar se a alternativa vale para cada elemento ou para a lista inteira. 2 min
  4. Tratar resultados opcionais com verificações de None Proteja o resultado de dict.get antes de usar operações que exigem um valor presente. 3 min
  5. Separar alternativas com isinstance Use isinstance para identificar qual alternativa de uma união está presente e aplicar operações compatíveis em cada ramo. 2 min
  6. Estreitar tipos com saídas antecipadas Use cláusulas de guarda para encerrar casos que não devem chegar ao processamento principal e deixar explícito qual tipo permanece. 2 min
  7. Reavaliar tipos quando o fluxo muda Acompanhe os tipos possíveis depois que caminhos se unem, terminam ou recebem uma nova atribuição. 2 min
  8. Aplicar o tratamento seguro em uma consulta tipada Integre argumentos opcionais, dict.get e estreitamento de tipos para corrigir uma função e verificá-la com Python e mypy. 4 min

O que você vai aprender

  • Anotar parâmetros, variáveis e retornos com uniões e valores que podem ser None.
  • Distinguir a possibilidade de receber None da possibilidade de omitir um argumento.
  • Restringir tipos com verificações de None, isinstance e saídas antecipadas.
  • Corrigir operações inseguras sobre resultados opcionais, como consultas com dict.get.

Antes de começar

  • Anotar coleções e estruturas aninhadas
  • Selecionar caminhos com if, elif e else
  • Validar entradas e sinalizar falhas com raise

Passo 1 de 8

Representar tipos alternativos com |

Use o operador | para declarar contratos que aceitam tipos alternativos e reconheça quando uma operação ainda não é segura.

Um contrato com alternativas

União de tipos

Use | quando um valor pode seguir um entre tipos alternativos. Por exemplo, int | str informa que o contrato aceita um número inteiro ou um texto.

A união descreve possibilidades; ela não converte valores. Se uma variável recebe "42", ela continua sendo str, mesmo que o contrato também admita int.

Leitura de int | str

Leia a anotação como duas possibilidades para o mesmo valor.

Diagrama mostrando um valor no centro ligado a dois caminhos alternativos: um número inteiro e um texto.

int | str permite uma alternativa ou outra, não transforma uma na outra.

Onde anotar a união

Variável, parâmetro e retorno

A mesma anotação pode aparecer em diferentes pontos do contrato.

python
codigo: int | str = 404


def exibir_codigo(valor: int | str) -> str:
    return f"Código: {valor}"


print(exibir_codigo(codigo))
print(exibir_codigo("indisponível"))

Na variável, a união limita os valores que podem ser atribuídos. No parâmetro, limita os argumentos aceitos. No retorno, informa que a chamada pode produzir qualquer uma das alternativas declaradas.

Como nas outras anotações, isso é um contrato para análise estática: Python não passa a validar automaticamente os valores em tempo de execução. O mypy pode apontar usos incompatíveis ao analisar o código.

Operações precisam servir para todas as alternativas

Antes de operar, considere as possibilidades

Enquanto valor pode ser int ou str, uma operação só é segura se funcionar para ambos os tipos. str(valor) é aceitável: tanto inteiros quanto textos podem ser representados como texto.

Já valor + 1 não é justificado pelo contrato: funciona para int, mas não para str. O mypy sinaliza esse tipo de risco; a anotação não escolhe qual alternativa chegou na execução.

Uma operação insegura

O comentário indica o ponto que o mypy deve rejeitar.

python
def aumentar(valor: int | str) -> int | str:
    # Erro: str não pode ser somada a int.
    return valor + 1


def rotulo(valor: int | str) -> str:
    # Seguro para as duas alternativas.
    return "Valor: " + str(valor)

Verifique o contrato antes da operação

Escolha a anotação

Uma função recebe um identificador que pode ser o inteiro 15 ou o texto "A15". Qual anotação representa esse parâmetro?

Reconheça o risco

Com valor: int | str, qual expressão ainda é insegura sem uma justificativa adicional no fluxo do código?

Passo 2 de 8

Separar aceitar None de permitir omissão

Diferencie o valor None de um argumento ausente e escreva assinaturas coerentes com cada contrato.

Duas permissões independentes

None não significa argumento omitido

Em uma anotação, str | None significa que o valor pode ser um texto ou None. Isso não diz se quem chama a função pode deixar o argumento de fora.

A possibilidade de omitir depende de existir um valor padrão na assinatura. Portanto, são duas decisões independentes:

  • Tipos aceitos: a anotação, como str ou str | None.
  • Argumento opcional na chamada: a presença de = algum_valor.

Leia a assinatura em duas dimensões

Compare o que cada parte da assinatura controla.

Diagrama com uma assinatura de função separada em anotação de tipo e valor padrão; a anotação indica os valores permitidos e o padrão indica se a chamada pode omitir o argumento.

A anotação define valores válidos; o padrão permite omissão do argumento.

Quatro contratos possíveis

Assinaturas e chamadas permitidas

Cada função ilustra uma combinação diferente. O corpo foi omitido porque o foco é o contrato do parâmetro.

python
# 1. Obrigatório; aceita somente str
def rotulo(nome: str) -> str:
    return nome

# rotulo()          # erro: argumento ausente
# rotulo(None)      # erro de tipo
rotulo("Ana")

# 2. Obrigatório; aceita str ou None
def apelido(nome: str | None) -> str:
    return "visitante" if nome is None else nome

# apelido()         # erro: argumento ausente
apelido(None)
apelido("Ana")

# 3. Pode ser omitido; aceita somente str
def saudacao(nome: str = "visitante") -> str:
    return f"Olá, {nome}!"

saudacao()
# saudacao(None)    # erro de tipo
saudacao("Ana")

# 4. Pode ser omitido; aceita str ou None
def mensagem(nome: str | None = None) -> str:
    return "Sem nome" if nome is None else f"Olá, {nome}!"

mensagem()
mensagem(None)
mensagem("Ana")

Dica

Compatibilidade obrigatória

O valor padrão também é um valor possível para o parâmetro. Assim, def mensagem(nome: str = None) é incoerente: None não pertence a str. Use str | None = None ou escolha um padrão que seja str.

Variáveis, parâmetros e retornos

O contrato vale em diferentes posições

A forma T | None pode aparecer onde um valor talvez esteja ausente: em uma variável local, em um parâmetro ou no retorno de uma função. Em todos os casos, ela descreve as alternativas possíveis do valor.

Exemplos com tipos concretos

Observe que somente consultar_id pode retornar None; já nome_digitado é uma variável que pode guardar esse valor.

python
nome_digitado: str | None = None


def consultar_id(usuario: str) -> int | None:
    if usuario == "ana":
        return 42
    return None


id_encontrado: int | None = consultar_id("bia")

Confira o contrato de cada assinatura

Associe a assinatura ao comportamento

Relacione cada assinatura à descrição correta.

Toque em um item e depois no par correspondente.

Complete a anotação

Complete somente a anotação: def limite(maximo: ___ = None) -> int:

Passo 3 de 8

Distinguir união de elementos e união de coleções

Use a posição de | e dos colchetes para expressar se a alternativa vale para cada elemento ou para a lista inteira.

Onde a união atua?

Colchetes definem o alcance

Compare as duas anotações:

  • list[int | str]: a união está dentro dos colchetes. Cada elemento da mesma lista pode ser int ou str.
  • list[int] | list[str]: a união está fora dos colchetes. O valor inteiro é uma lista de inteiros ou uma lista de textos.

Portanto, mover | muda o contrato.

Dois contratos diferentes

A posição de | indica se a escolha ocorre elemento a elemento ou para a coleção como um todo.

Comparação visual entre uma lista mista de números e textos e a alternativa entre uma lista só de números ou uma lista só de textos.

Dentro dos colchetes: alternativas para cada elemento. Fora: alternativas para a lista inteira.

União nos elementos

Exemplo

Uma lista pode misturar valores

valores: list[int | str] = [10, "dez", 20, "vinte"]

Aqui, cada posição aceita uma das duas alternativas. Por isso, inteiros e textos podem aparecer juntos na mesma lista.

Também seriam compatíveis: [], [1, 2] e ["a", "b"].

Dica

Leia de dentro para fora

Em list[int | str], primeiro leia o tipo de um elemento: int | str. Depois leia list[...]: uma lista desses elementos.

União entre listas

Exemplo

A lista inteira escolhe uma alternativa

numeros: list[int] | list[str] = [10, 20, 30]
textos: list[int] | list[str] = ["dez", "vinte"]

Cada valor é uma lista uniforme: ou todos os elementos são int, ou todos são str.

Já [10, "vinte"] não corresponde a esse contrato, pois mistura os tipos na mesma lista.

Compare valores literais

Para escolher a anotação, observe o formato permitido:

  • Quer permitir [1, "dois"]? Use list[int | str].
  • Quer permitir [1, 2] ou ["um", "dois"], mas não uma mistura? Use list[int] | list[str].

Essa comparação descreve contratos por valores literais; não depende de regras de compatibilidade entre variáveis de listas.

Escolha o contrato

Lista que aceita mistura

Qual anotação representa uma lista etiquetas que pode conter valores como [101, "novo", 205]?

Passo 4 de 8

Tratar resultados opcionais com verificações de None

Proteja o resultado de dict.get antes de usar operações que exigem um valor presente.

Uma consulta pode não encontrar a chave

O contrato de get sem padrão

Mesmo que um dicionário armazene apenas inteiros, uma busca com get sem valor padrão pode não encontrar a chave. Por isso, o resultado admite None.

Em dict[str, int], a expressão pontos.get("ana") tem tipo int | None: o int vem de um valor encontrado; o None, de uma chave ausente.

Dois resultados possíveis

A anotação dos valores do dicionário não elimina a possibilidade de a chave consultada estar ausente.

Diagrama de uma consulta em dicionário: uma chave existente leva a um valor inteiro e uma chave inexistente leva a None.

get pode devolver um valor armazenado ou None quando não encontra a chave.

Resultado opcional

A operação abaixo seria insegura sem uma verificação.

python
pontos: dict[str, int] = {"ana": 12, "bia": 7}

pontuacao: int | None = pontos.get("cai")
print(pontuacao)  # None

# pontuacao + 1  # inseguro: pontuacao pode ser None

Verifique antes de operar

Estreitamento em cada ramo

Guarde a consulta em uma variável local e teste-a com is None. No ramo verdadeiro, ela é None. No else, essa possibilidade foi excluída: ali, pontuacao é int e pode participar da soma.

Você também pode escrever a condição positiva como is not None; nesse caso, o ramo verdadeiro recebe o valor presente.

Operação somente com valor presente

A soma está no ramo em que None não é mais uma possibilidade.

python
pontos: dict[str, int] = {"ana": 12, "bia": 7}

pontuacao: int | None = pontos.get("ana")

if pontuacao is None:
    print("Pessoa não encontrada")
else:
    proxima_pontuacao = pontuacao + 1
    print(f"Próxima pontuação: {proxima_pontuacao}")

Ausência não é valor falso

Atenção

Evite usar a verdade do valor para detectar ausência

if pontuacao: não responde à pergunta “a chave foi encontrada?”. Um valor presente pode ser 0, que é falso em um contexto booleano. O mesmo ocorre com "" em dicionários de textos.

Para verificar a ausência produzida por get, use is None ou is not None.

0 e texto vazio continuam presentes

Nos dois exemplos, a chave existe; apenas seus valores são falsos em uma condição booleana.

python
quantidades: dict[str, int] = {"maçã": 0}
quantidade: int | None = quantidades.get("maçã")

if quantidade is None:
    print("Produto ausente")
else:
    print(f"Quantidade registrada: {quantidade}")  # 0

nomes: dict[str, str] = {"apelido": ""}
apelido: str | None = nomes.get("apelido")

if apelido is None:
    print("Chave ausente")
else:
    print("A chave existe, mesmo com texto vazio")

Pratique a proteção

Complete a condição

Complete a condição para mostrar a mensagem apenas quando a consulta não encontrar a chave:

estoque: dict[str, int] = {"caneta": 0}
quantidade: int | None = estoque.get("caderno")

if quantidade ___:
    print("Produto não encontrado")
else:
    print(quantidade + 1)

Diferencie presença de valor booleano

Com o código da atividade, qual mensagem seria exibida se a consulta fosse estoque.get("caneta")?

Passo 5 de 8

Separar alternativas com isinstance

Use isinstance para identificar qual alternativa de uma união está presente e aplicar operações compatíveis em cada ramo.

Uma condição que evidencia o tipo

Do contrato amplo à operação específica

Uma anotação como int | str informa que a variável pode conter uma das duas alternativas. Antes de usar uma operação exclusiva de um tipo, use isinstance para descobrir qual alternativa está presente naquele ramo.

Em if isinstance(valor, int):, o ramo verdadeiro trabalha com int. Como a união simples tem apenas int e str, no else resta str.

Fluxo de estreitamento

A condição divide as alternativas ainda possíveis em ramos seguros.

Diagrama de fluxo: valor anotado como int ou str chega a uma verificação isinstance de int; o ramo verdadeiro contém somente int e o ramo falso somente str.

Cada ramo recebe um contrato mais específico do que o contrato inicial.

Operações no ramo compatível

int em um ramo, str no outro

A multiplicação e upper() não são justificadas para os dois tipos ao mesmo tempo. Elas ficam nos ramos que comprovam seu tipo.

python
def apresentar(valor: int | str) -> str:
    if isinstance(valor, int):
        dobro = valor * 2
        return f"Número dobrado: {dobro}"
    else:
        destaque = valor.upper()
        return f"Texto em destaque: {destaque}"

print(apresentar(7))       # Número dobrado: 14
print(apresentar("azul"))  # Texto em destaque: AZUL

Dica

Leia o else pelo que restou

O else não significa “qualquer outro valor” neste contrato. Como valor começou como int | str e o if confirmou int, ali resta somente str.

Estreitamento em etapas

Primeiro exclua None; depois separe os demais

Quando o valor é int | str | None, uma verificação de ausência vem antes: após confirmar que não é None, restam int | str. Então isinstance separa essas duas alternativas.

Cada operação aparece somente depois da evidência que a justifica.

Dois testes, contratos cada vez menores

O segundo if é alcançado apenas quando dado não é None.

python
def descrever(dado: int | str | None) -> str:
    if dado is None:
        return "Sem dado"

    if isinstance(dado, int):
        return f"Quadrado: {dado ** 2}"
    else:
        return f"Caracteres: {len(dado)}"

Associe o ponto do fluxo ao tipo possível

Considere a função descrever acima. Relacione cada situação ao contrato de dado naquele ponto.

Toque em um item e depois no par correspondente.

Passo 6 de 8

Estreitar tipos com saídas antecipadas

Use cláusulas de guarda para encerrar casos que não devem chegar ao processamento principal e deixar explícito qual tipo permanece.

Cláusula de guarda: trate e encerre

Remova o caso ausente do caminho principal

Uma cláusula de guarda trata logo no início um caso que não seguirá para o processamento principal. Se o parâmetro é str | None, teste None e termine esse ramo com return. Depois da guarda, o único tipo possível para nome é str.

Fluxo depois de um return antecipado

O ramo que recebe None termina; apenas o ramo com texto alcança upper().

Diagrama de fluxo de uma função: entrada nome do tipo str ou None; o caminho None passa por return e termina, enquanto o caminho str segue para a operação upper.

Um caminho encerrado não alcança as operações posteriores.

Retorno para um caso previsto

O retorno representa uma resposta válida para a ausência de nome.

python
def saudacao(nome: str | None) -> str:
    if nome is None:
        return "Olá, visitante!"

    return f"Olá, {nome.upper()}!"

print(saudacao(None))      # Olá, visitante!
print(saudacao("Lia"))     # Olá, LIA!

Quando a guarda deve sinalizar falha

return ou raise?

Escolha a saída conforme o contrato da função. Use return quando a alternativa é prevista e há uma resposta útil para ela. Use raise quando aquela alternativa viola uma exigência da função. Nos dois casos, o ramo termina: o processamento seguinte só é alcançado pelos tipos restantes.

Rejeitando None antes do cálculo

Aqui, a função exige uma idade numérica. None não tem resposta alternativa: é uma entrada inválida.

python
def ano_de_nascimento(idade: int | None, ano_atual: int) -> int:
    if idade is None:
        raise ValueError("A idade é obrigatória.")

    return ano_atual - idade

print(ano_de_nascimento(30, 2025))  # 1995

Dica

A condição sozinha não basta

Um if idade is None: sem return ou raise não elimina None do trecho posterior: esse caminho ainda pode continuar até ele.

Organize a cláusula de guarda

Monte a função

Coloque os blocos na ordem que forma uma função segura para apresentar um código opcional.

  1. return "Código indisponível"
  2. return codigo.upper()
  3. if codigo is None:
  4. def exibir_codigo(codigo: str | None) -> str:

Passo 7 de 8

Reavaliar tipos quando o fluxo muda

Acompanhe os tipos possíveis depois que caminhos se unem, terminam ou recebem uma nova atribuição.

O estreitamento depende do ponto do fluxo

Uma informação local

Uma anotação como int | str continua sendo o contrato da variável. O estreitamento obtido por uma condição vale apenas onde o fluxo fornece essa evidência.

Quando dois caminhos que continuam se reencontram, o mypy combina os tipos que podem chegar àquele ponto. Por isso, uma união pode voltar a ser relevante após um if.

Caminhos que se reencontram

Diagrama de fluxo: uma variável int ou str é separada por isinstance; o ramo int chega ao fim do if e o ramo str também; os dois se unem depois, onde ambos os tipos voltam a ser possíveis.

Depois da junção, chegam os valores dos dois ramos que continuam.

Os dois ramos alcançam a junção

Use reveal_type somente ao verificar o arquivo com mypy; remova-o antes da execução normal.

python
def mostrar(valor: int | str) -> None:
    if isinstance(valor, int):
        reveal_type(valor)  # mypy: builtins.int
        print(valor + 1)
    else:
        reveal_type(valor)  # mypy: builtins.str
        print(valor.upper())

    reveal_type(valor)  # mypy: builtins.int | builtins.str
    # valor.upper() seria inseguro aqui

Caminhos encerrados não voltam à junção

Return e raise removem possibilidades

Um caminho que termina com return ou raise não alcança o código seguinte. Assim, seu tipo não participa da junção.

No exemplo, após retornar no caso de None, o restante da função recebe somente int. A anotação do parâmetro não mudou; o fluxo eliminou uma alternativa naquele ponto.

Apenas int continua

python
def dobrar(valor: int | None) -> int:
    if valor is None:
        return 0

    reveal_type(valor)  # mypy: builtins.int
    return valor * 2

Preveja o tipo

Em dobrar, qual tipo o mypy conhece para valor imediatamente antes de return valor * 2?

Uma atribuição pode ampliar as possibilidades

Reavalie depois de atribuir

O tipo conhecido também é atualizado após uma nova atribuição compatível com a anotação declarada. Se uma variável declarada como str | None recebe None novamente, operações de texto deixam de estar justificadas até outra verificação.

Não basta lembrar que a variável já foi str em um trecho anterior: analise o ponto exato da operação.

None volta a ser possível

python
def preparar(nome: str | None, limpar: bool) -> str:
    if nome is None:
        nome = "visitante"

    reveal_type(nome)  # mypy: builtins.str

    if limpar:
        nome = None

    reveal_type(nome)  # mypy: builtins.str | None

    if nome is None:
        return "sem nome"
    return nome.title()

Dica

Regra prática

Antes de chamar um método ou aplicar um operador específico, pergunte: quais caminhos e quais atribuições podem chegar aqui? A operação precisa ser válida para todos os tipos ainda possíveis.

Teste seu raciocínio de fluxo

Explique a nova verificação

Analise o código e explique por que uma nova verificação é necessária na linha marcada:

<code>def exibir(codigo: str | None, redefinir: bool) -> str:
if codigo is None:
codigo = "pendente"

if redefinir:
codigo = None

# linha marcada
return codigo.upper()</code>

Escreva pelo menos 80 caracteres (0/80).

Passo 8 de 8

Aplicar o tratamento seguro em uma consulta tipada

Integre argumentos opcionais, dict.get e estreitamento de tipos para corrigir uma função e verificá-la com Python e mypy.

Um contrato e três decisões

Mapeie os tipos pelo fluxo

Nesta função, chave: str | None = None aceita uma chave de texto ou None; o = None permite que o argumento seja omitido. Ao chamar apresentar(), a função recebe o padrão None. Ao chamar apresentar(None), o chamador fornece None explicitamente. Dentro desta função, ambos seguem o mesmo caso de “nenhuma chave informada”.

Depois da guarda para chave, catalogo.get(chave) tem tipo int | str | None: a chave pode não existir. Só depois de excluir None é seguro separar int de str com isinstance.

Fluxo de estreitamento

Cada ramo elimina possibilidades antes de executar uma operação específica.

Diagrama de fluxo com uma entrada opcional que segue para uma saída antecipada quando está ausente; uma consulta ao catálogo segue para outra saída quando não encontra valor; os valores encontrados se dividem em rota numérica e rota de texto, antes de gerar uma resposta em texto.

As saídas antecipadas removem None dos caminhos que continuam. No trecho final, cada operação é justificada pelo tipo restante.

Prática: corrija o script localmente

Sua tarefa

No seu editor, crie um arquivo chamado consulta_tipado.py com o código abaixo. Substitua os # TODO sem usar Any, cast ou supressões do mypy.

Use saídas antecipadas para: (1) tratar chave is None; (2) tratar uma chave ausente; e então use isinstance(valor, int) antes da soma. No ramo restante, aplique upper() ao texto.

Código-base completo

Corrija somente os trechos marcados com TODO.

python
catalogo: dict[str, int | str] = {
    "itens": 4,
    "status": "ativo",
    "zero": 0,
    "vazio": "",
}


def apresentar(chave: str | None = None) -> str:
    # TODO: encerre o caso em que chave é None.

    valor = catalogo.get(chave)

    # TODO: encerre o caso em que a chave não foi encontrada.

    # TODO: no caso int, retorne o valor acrescido de 1.
    # TODO: no outro caso, retorne o texto em maiúsculas.
    return f"{chave}: {valor + 1}"


print(apresentar("itens"))
print(apresentar("status"))
print(apresentar("zero"))
print(apresentar("vazio"))
print(apresentar("inexistente"))
print(apresentar())
print(apresentar(None))

Confira a correção e verifique

Uma solução tipada

Compare com sua versão depois de tentar. A mesma guarda que torna a chamada de get válida também elimina None no restante da função.

python
catalogo: dict[str, int | str] = {
    "itens": 4,
    "status": "ativo",
    "zero": 0,
    "vazio": "",
}


def apresentar(chave: str | None = None) -> str:
    if chave is None:
        return "Nenhuma chave informada"

    valor = catalogo.get(chave)
    if valor is None:
        return f"{chave}: ausente"

    if isinstance(valor, int):
        return f"{chave}: {valor + 1} unidades"

    return f"{chave}: {valor.upper()}"


print(apresentar("itens"))
print(apresentar("status"))
print(apresentar("zero"))
print(apresentar("vazio"))
print(apresentar("inexistente"))
print(apresentar())
print(apresentar(None))

Exemplo

Execute e compare

No terminal, na pasta do arquivo, execute:

python consulta_tipado.py
python -m mypy --strict consulta_tipado.py

A execução deve produzir, nesta ordem:

itens: 5 unidades
status: ATIVO
zero: 1 unidades
vazio: 
inexistente: ausente
Nenhuma chave informada
Nenhuma chave informada

O mypy deve terminar sem erros. Note que 0 e "" chegam aos ramos de inteiro e texto: eles são valores presentes, portanto não devem ser tratados com if not valor.

Dica

Por que as guardas funcionam?

Após if chave is None: return, o único tipo possível para chave é str. Após if valor is None: return, valor só pode ser int | str. Depois de isinstance(valor, int), o ramo final recebe str. Cada return encerra um caminho, então ele não contribui para os tipos possíveis adiante.

Revisão final

Relate sua verificação

Depois de executar sua versão, relate: quais foram os resultados para inteiro, texto, 0, texto vazio, chave ausente, argumento omitido e None explícito? Justifique por que usou is None e isinstance, em vez de um teste de valor booleano.

Escreva pelo menos 180 caracteres (0/180).

Resumo

Critérios para consultas seguras

Use o contrato e o fluxo juntos para justificar cada operação.

  • Use T | None quando o valor pode ser None; um valor padrão compatível decide se o argumento pode ser omitido.
  • Uma consulta com dict.get sem padrão pode produzir None, mesmo quando os valores do dicionário são int | str.
  • Teste ausência com is None, não com a verdade do valor: 0 e "" podem ser dados válidos.
  • Use isinstance para separar alternativas e aplique soma ou métodos de texto apenas no ramo compatível.
  • Um return ou raise antecipado remove daquele restante do fluxo a alternativa que já foi tratada.

Tutorial concluído

Parabéns! Você concluiu: Tratar valores opcionais e uniões de tipos

Muito bem! Agora você consegue declarar alternativas de tipo, distinguir ausência de omissão e justificar cada operação pelos tipos que permanecem possíveis naquele ponto do código.

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso