Pular para o conteúdo

Como Usar as Dicas de Tipo Python para Listas e Tuplas

[

Como usar Dicas de Tipo Python para Múltiplos Tipos de Retorno

por Claudia Ng, 30 de Outubro de 2023

No Python, a dica de tipo é um recurso opcional, porém útil, para tornar o seu código mais fácil de ler, entender e depurar. Com as dicas de tipo, você informa aos outros desenvolvedores os tipos de dados esperados para variáveis, argumentos de função e valores de retorno. Conforme você escreve código para aplicativos que exigem maior flexibilidade, pode ser necessário especificar múltiplos tipos de retorno para tornar o seu código mais robusto e adaptável a diferentes situações.

Você encontrará diferentes casos de uso em que pode desejar indicar múltiplos tipos de retorno dentro de uma única função em Python. Em outras palavras, os dados retornados podem variar em tipo. Neste tutorial, você verá exemplos de como especificar múltiplos tipos de retorno para uma função que analisa uma string de um endereço de e-mail para obter o nome de domínio.

Além disso, você verá exemplos de como especificar dicas de tipo para funções de retorno de chamada ou funções que aceitam outra função como entrada. Com esses exemplos, você estará preparado para expressar dicas de tipo na programação funcional.

Observação: Normalmente, você deseja trabalhar com funções que são flexíveis quanto aos tipos de argumentos que aceitam, enquanto são específicas sobre o tipo de valor de retorno. Por exemplo, uma função pode aceitar qualquer iterável, como uma lista, tupla ou gerador, mas sempre retornar uma lista.

Usando as Dicas de Tipo do Python para um Único Dado de Tipos Alternativos

  1. Valores opcionais: Uma função pode, às vezes, não retornar valor, nesse caso, você pode usar dicas de tipo para indicar a ocasional ausência de um valor de retorno.

  2. Tratamento de erros: Quando uma função encontra um erro, pode ser desejável retornar um objeto de erro específico que seja diferente do tipo de retorno dos resultados normais. Fazer isso pode ajudar outros desenvolvedores a lidar com erros no código.

  3. Flexibilidade: Ao projetar e escrever código, geralmente queremos que ele seja versátil, flexível e reutilizável. Isso pode significar escrever funções que possam lidar com uma variedade de tipos de dados. Especificar isso nas dicas de tipo ajuda outros desenvolvedores a entender a versatilidade do seu código e seus usos pretendidos em diferentes casos.

No exemplo abaixo, você aprenderá como especificar dicas de tipo para uma função que verifica se uma string contém apenas dígitos ou letras. A função check_string() verifica se a string passada como argumento contém apenas letras ou apenas dígitos. Se contiver apenas letras, a função retorna uma string. Se contiver apenas dígitos, a função retorna um inteiro. Caso contrário, a função retorna None.

from typing import Union
def check_string(data: str) -> Union[str, int, None]:
if data.isalpha():
return data
elif data.isdigit():
return int(data)
else:
return None

Neste exemplo, a dica de tipo Union[str, int, None] indica que a função check_string() pode retornar uma string, um inteiro ou None.

Você pode testar essa função com diferentes entradas, como:

print(check_string("abc")) # Output: abc (str)
print(check_string("123")) # Output: 123 (int)
print(check_string("abc123")) # Output: None

No primeiro exemplo, a função retorna uma string, no segundo exemplo retorna um inteiro e no terceiro exemplo retorna None.

Usando dicas de tipo como essa, você pode indicar claramente os possíveis tipos de retorno da função, facilitando a compreensão do código por outros desenvolvedores que o utilizam.

Usando as Dicas de Tipo do Python para Múltiplos Dados de Diferentes Tipos

Nesta seção, você aprenderá como escrever dicas de tipo para funções que podem retornar múltiplos dados de diferentes tipos. Este cenário é útil quando você deseja retornar vários dados relacionados de diferentes tipos em uma única função.

Um exemplo comum disso é uma função que converte uma string para diferentes formatos, como inteiro, float e data. A função convert_data() recebe uma string como entrada e retorna uma lista contendo o valor convertido para cada um dos tipos mencionados.

from typing import List, Union
def convert_data(data: str) -> List[Union[int, float, datetime.date]]:
int_value = int(data)
float_value = float(data)
date_value = datetime.datetime.strptime(data, "%Y-%m-%d").date()
return [int_value, float_value, date_value]

Neste exemplo, a dica de tipo List[Union[int, float, datetime.date]] indica que a função convert_data() retorna uma lista contendo valores que podem ser do tipo int, float ou datetime.date.

Você pode testar essa função com diferentes entradas de string, como:

print(convert_data("123"))
# Saida: [123 (int), 123.0 (float), 2023-10-30 (date)]

No exemplo acima, a função convert_data() recebe a string “123” como entrada e retorna uma lista contendo o valor convertido para inteiro (123), valor de ponto flutuante (123.0) e valor de data (30 de outubro de 2023).

Usando dicas de tipo como List[Union[int, float, datetime.date]], você deixa claro que a função pode retornar múltiplos dados de diferentes tipos, o que facilita a compreensão do código e ajuda a evitar erros de tipo ao trabalhar com os valores retornados da função.

Declarando uma Função para Receber um Callback

Outro caso de uso comum para dicas de tipo é quando você deseja declarar uma função que recebe uma função de retorno de chamada como argumento. Isso é comumente usado em programação assíncrona ou em bibliotecas que requerem o uso de callbacks para executar ações específicas quando um evento ocorre.

Por exemplo, vamos considerar uma função process_data() que recebe uma função de retorno de chamada callback como argumento. Essa função recebe um valor de entrada (data) e chama a função de retorno de chamada, passando esse valor como argumento.

from typing import Callable
def process_data(data: int, callback: Callable[[int], None]) -> None:
callback(data)

Neste exemplo, a dica de tipo Callable[[int], None] indica que a função callback passada como argumento deve receber um inteiro como argumento e não retornar nenhum valor.

Você pode usar essa função process_data() com diferentes funções de retorno de chamada. Por exemplo:

def print_data(data: int) -> None:
print("Data:", data)
process_data(123, print_data) # Output: Data: 123

No exemplo acima, a função process_data() é chamada com o valor 123 e a função de retorno de chamada print_data. A função print_data é então chamada dentro da função process_data, passando o valor 123 como argumento e exibindo-o na saída.

Com as dicas de tipo Callable[[int], None], você pode garantir que a função process_data() seja usada corretamente com as funções de retorno de chamada adequadas.

Anotando o Valor de Retorno de uma Função Factory

Outro caso de uso para as dicas de tipo é quando você está trabalhando com funções de fábrica, que são funções que retornam outras funções. Essas funções de fábrica podem ser úteis em situações em que você precisa criar dinamicamente uma função com base em alguma entrada ou configuração.

Por exemplo, vamos considerar uma função de fábrica create_multiplier() que recebe um argumento de entrada factor e retorna uma função que multiplica seu argumento de entrada pelo fator fornecido.

from typing import Callable
def create_multiplier(factor: int) -> Callable[[int], int]:
def multiplier(value: int) -> int:
return value * factor
return multiplier

Neste exemplo, a dica de tipo Callable[[int], int] indica que a função retornada pela função de fábrica create_multiplier() deve receber um valor inteiro como argumento e retornar um valor inteiro.

Você pode usar essa função de fábrica para criar funções multiplicadoras com diferentes fatores, como:

multiply_by_two = create_multiplier(2)
multiply_by_three = create_multiplier(3)
print(multiply_by_two(5)) # Output: 10
print(multiply_by_three(5)) # Output: 15

No exemplo acima, duas funções multiplicadoras são criadas usando a função de fábrica create_multiplier(). Uma função que multiplica por dois (multiply_by_two) e outra que multiplica por três (multiply_by_three). Essas funções retornadas são então chamadas com um valor de entrada (5) e seus resultados são exibidos na saída.

Ao usar as dicas de tipo Callable[[int], int], você fornece informações claras sobre o tipo de retorno das funções retornadas pela função de fábrica.

Anotando os Valores Gerados por um Gerador

Outro caso de uso para as dicas de tipo é quando você tem um gerador (generator) que gera valores de diferentes tipos. Ao anotar os valores gerados por um gerador, você pode fornecer informações sobre os tipos esperados dos valores no momento da iteração.

Vamos considerar um exemplo de um gerador generate_values() que gera uma sequência de valores, alternando entre inteiros e strings.

from typing import Generator, Union
def generate_values() -> Generator[Union[int, str], None, None]:
yield 123
yield "abc"
yield 456
yield "def"

Neste exemplo, a dica de tipo Generator[Union[int, str], None, None] indica que o gerador generate_values() gera valores que podem ser de tipo int ou str.

Você pode iterar sobre o gerador usando um loop for, como:

for value in generate_values():
print(value)

A saída desse loop será:

123
abc
456
def

Ao usar as dicas de tipo Generator[Union[int, str], None, None], você informa aos outros desenvolvedores que os valores gerados pelo gerador podem ser de tipo int ou str, facilitando o entendimento do código.

Melhorando a Legibilidade com Tipos Aliases

Em alguns casos, a especificação de tipos pode se tornar complicada ou dificultar a legibilidade do código. Para lidar com essa situação, o Python oferece o recurso de alias de tipo (type alias), que permite criar um nome alternativo para um tipo específico.

Vamos considerar um exemplo em que você tem uma função calculate_discount() que recebe um preço (price) e um desconto (discount) e retorna o preço com desconto.

from typing import Union
def calculate_discount(price: float, discount: float) -> float:
return price * (1 - discount)

Neste exemplo, os argumentos e o valor de retorno são todos do tipo float. No entanto, pode ser mais legível usar um alias de tipo para especificar que Price e Discount são do tipo float. Você pode fazer isso usando o TypeAlias:

from typing import TypeAlias
FloatNum = TypeAlias(float)
def calculate_discount(price: FloatNum, discount: FloatNum) -> FloatNum:
return price * (1 - discount)

Neste exemplo, o TypeAlias FloatNum é definido como o alias de tipo float. O alias FloatNum é então usado nos argumentos da função calculate_discount() e no valor de retorno. Isso torna o código mais legível e facilita o entendimento das definições de tipo.

Aproveitando Ferramentas para Verificação Estática de Tipo

Além de usar as dicas de tipo durante o desenvolvimento, você pode aproveitar ferramentas de verificação estática de tipo, como o mypy, para verificar a correção das dicas de tipo no seu código Python.

O mypy é uma ferramenta de análise estática que verifica a precisão das dicas de tipo em programas Python. Ele pode detectar erros de tipo e ajudar a evitar problemas de execução relacionados a tipos.

Para usar o mypy, você precisa instalá-lo e executá-lo em seu código Python. Ele analisará o seu código em busca de possíveis erros de tipo com base nas dicas de tipo especificadas.

Por exemplo, se você tiver um arquivo de código chamado example.py, poderá executar o mypy nesse arquivo usando o seguinte comando:

mypy example.py

O mypy fornecerá informações detalhadas sobre os erros de tipo encontrados ou confirmará que o código está correto em termos de conformidade com as dicas de tipo.

O uso de ferramentas como o mypy é altamente recomendado ao trabalhar com dicas de tipo em seu código Python, pois ajuda a garantir a precisão e a correção das definições de tipo.

Conclusão

Neste tutorial, você aprendeu como usar as dicas de tipo do Python para especificar múltiplos tipos de retorno em funções. Você viu exemplos de como indicar dicas de tipo para um único dado de tipos alternativos, múltiplos dados de diferentes tipos, funções que recebem callbacks, o valor de retorno de uma função de fábrica e os valores gerados por um gerador. Além disso, você aprendeu sobre aliases de tipo e como aproveitar ferramentas de verificação estática de tipo para garantir a correção das suas dicas de tipo.

As dicas de tipo são uma ferramenta poderosa que pode melhorar a legibilidade, a manutenção e a confiabilidade do seu código Python. Ao incorporar as dicas de tipo nas suas práticas de programação, você se beneficia de um código mais robusto e de uma colaboração mais eficiente com outros desenvolvedores.

Continue explorando as dicas de tipo e suas aplicações em diferentes contextos e projetos para aprimorar ainda mais suas habilidades em Python.