Typing em Python: Melhorando a Legibilidade do Código

PythonBeginner
Pratique Agora

Introdução

Neste tutorial, você aprenderá como usar o módulo typing do Python para adicionar dicas de tipo ao seu código. As dicas de tipo ajudam a tornar seu código mais legível e fácil de manter, indicando explicitamente os tipos de entrada e saída esperados de suas funções.

Tipos Básicos

As dicas de tipo são um recurso introduzido no Python 3.5, e o módulo typing foi adicionado no Python 3.5.2 para fornecer um conjunto padrão de anotações de tipo. Importe os tipos relevantes do módulo typing para começar a usar dicas de tipo.

from typing import List, Tuple, Dict

As dicas de tipo para tipos básicos são diretas. Basta usar o próprio tipo como uma dica.

Abra o shell do Python digitando o seguinte comando no terminal.

python3
  1. Defina uma variável do tipo int, atribua um valor a ela e imprima-a.
age: int = 25
print(age) #Output: 25
  1. Defina uma variável do tipo float, atribua um valor e imprima-a.
temperature: float = 98.6
print(temperature) ## Output: 98.6
  1. Defina uma variável do tipo bool, atribua um valor e imprima-a.
is_raining: bool = True
print(is_raining) ## Output: True
  1. Defina uma variável do tipo str, atribua um valor e imprima-a.
def greet(name: str) -> str:
    return f"Hello, {name}!"

print(greet("Alice")) ## Output: Hello, Alice!
  1. Defina uma função que recebe dois argumentos do tipo int, multiplica-os e retorna o resultado como um int.
def multiply(x: int, y: int) -> int:
    return x * y

result = multiply(5, 10)
print(result) ## Output: 50

Containers e Genéricos

As dicas de tipo para tipos de contêiner (como listas, dicionários e conjuntos) podem ser mais específicas usando genéricos.

Dicas: Os experimentos com números de série 1-3 podem ser implementados no shell do Python, e os experimentos com número de série 4 são implementados no WebIDE.

  1. Defina uma variável do tipo List[int], atribua alguns valores e imprima-a.
from typing import List
numbers: List[int] = [1, 2, 3, 4, 5]
print(numbers) ## Output: [1, 2, 3, 4, 5]
  1. Defina uma variável do tipo Dict[str, int], atribua alguns pares chave-valor e imprima-a.
from typing import Dict
ages: Dict[str, int] = {"Alice": 25, "Bob": 30, "Charlie": 35}
print(ages) ## Output: {'Alice': 25, 'Bob': 30, 'Charlie': 35}
  1. Defina uma variável do tipo Tuple[str, int, float], atribua alguns valores e imprima-a.
from typing import Tuple
person: Tuple[str, int, float] = ("Alice", 25, 5.7)
print(person) ## Output: ('Alice', 25, 5.7)
  1. Defina uma função que recebe uma lista de inteiros como argumento e retorna o resultado como um novo conjunto de inteiros.

Crie um projeto chamado list_to_set.py no WebIDE e insira o seguinte conteúdo.

from typing import List, Set

def get_unique_elements(elements: List[int]) -> Set[int]:
    return set(elements)

numbers = [1, 2, 2, 3, 4, 4, 4, 5]
unique_numbers = get_unique_elements(numbers)
print(unique_numbers)  ## Output: {1, 2, 3, 4, 5}

Use o seguinte comando para executar o script.

python list_to_set.py

Tipos Definidos pelo Usuário

Você também pode usar tipos e classes personalizados como dicas de tipo.

Dicas: Este experimento é implementado no WebIDE.

  1. Defina uma classe Person com atributos tipados name (str) e age (int) e um método get_summary que retorna uma string resumindo o nome e a idade da pessoa.

Crie um projeto chamado str_and_int_to_str.py no WebIDE e insira o seguinte conteúdo.

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    def get_summary(self) -> str:
        return f"{self.name} is {self.age} years old."

person1 = Person("Alice", 25)
print(person1.get_summary()) ## Output: Alice is 25 years old.

Use o seguinte comando para executar o script.

python str_and_int_to_str.py
  1. Defina uma classe Point com atributos tipados x e y, ambos do tipo float, e um método distance que recebe outro ponto como argumento e retorna a distância entre os dois pontos.

Crie um projeto chamado other_to_float.py no WebIDE e insira o seguinte conteúdo.

import math

class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y
    def distance(self, other: "Point") -> float:
        return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)

point1 = Point(0, 0)
point2 = Point(3, 4)
print(point1.distance(point2)) ## Output: 5.0

Use o seguinte comando para executar o script.

python other_to_float.py

Type Aliases (Sinônimos de Tipos)

Type aliases (alias de tipos) podem criar dicas de tipo mais legíveis, especialmente para tipos complexos.

Crie um projeto chamado type_aliases.py no WebIDE e insira o seguinte conteúdo.

from typing import List, Tuple

Coordinate = Tuple[float, float]
Path = List[Coordinate]

def get_distance(coord1: Coordinate, coord2: Coordinate) -> float:
    return ((coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2)**0.5

start = (0, 0)
end = (3, 4)
print(get_distance(start, end))  ## Output: 5.0

Use o seguinte comando para executar o script.

python type_aliases.py

Opcional e Nenhum (None)

O tipo Optional pode ser usado quando um valor pode ser de um tipo específico ou None.

  1. Defina uma função que recebe um argumento int opcional, multiplica-o por 2 se não for None e retorna o resultado como um int ou None se a entrada for None.

Crie um projeto chamado option_and_none_1.py no WebIDE e insira o seguinte conteúdo.

from typing import Optional

def double_or_none(number: Optional[int]) -> Optional[int]:
    if number is not None:
        return number * 2
    else:
        return None

result1 = double_or_none(5)
result2 = double_or_none(None)
print(result1, result2) ## Output: 10 None

Use o seguinte comando para executar o script.

python option_and_none_1.py
  1. Defina uma classe Person com um atributo tipado address, que pode ser uma string de endereço válida ou None.

Crie um projeto chamado option_and_none_2.py no WebIDE e insira o seguinte conteúdo.

from typing import Optional

class Person:
    def __init__(self, name: str, age: int, address: Optional[str]):
        self.name = name
        self.age = age
        self.address = address

person1 = Person("Alice", 25, "123 Main St")
person2 = Person("Bob", 30, None)
print(person1.name, person1.age, person1.address) ## Output: Alice 25 123 Main St
print(person2.name, person2.age, person2.address) ## Output: Bob 30 None

Use o seguinte comando para executar o script.

python option_and_none_2.py

Callable (Chamável)

O tipo Callable é usado para especificar o tipo de uma função ou método.

Crie um projeto chamado callable.py no WebIDE e insira o seguinte conteúdo.

from typing import Callable

def apply_function(value: int, func: Callable[[int], int]) -> int:
    return func(value)

def double(x: int) -> int:
    return x * 2

print(apply_function(5, double))  ## Output: 10

Use o seguinte comando para executar o script.

python callable.py

Typeddict

TypedDict permite criar dicionários personalizados com chaves e tipos de valor específicos.

Dicas: TypedDict foi introduzido no Python 3.8, então você precisa estar executando o Python 3.8 ou posterior para usá-lo.

Aqui está um exemplo:

Crie um projeto chamado typeddict.py no WebIDE e insira o seguinte conteúdo.

from typing import TypedDict

class PersonInfo(TypedDict):
    name: str
    age: int

def greet(person: PersonInfo) -> str:
    return f"Hello, {person['name']}! You are {person['age']} years old."

alice_info: PersonInfo = {"name": "Alice", "age": 30}
print(greet(alice_info))  ## Output: Hello, Alice! You are 30 years old.

Use o seguinte comando para executar o script.

python typeddict.py

Newtype

NewType é uma dica de tipo (type hint) do módulo typing em Python que permite criar um novo tipo que é apenas um wrapper (invólucro) em torno de um tipo existente. Isso pode ser útil para adicionar mais significado semântico a variáveis e argumentos de função.

Aqui está um exemplo:

Crie um projeto chamado newtype.py no WebIDE e insira o seguinte conteúdo.

Em seguida, execute o seguinte script Python.

from typing import NewType

UserId = NewType("UserId", int)
OrderId = NewType("OrderId", int)

def get_order(order_id: OrderId) -> str:
    return f"Order with ID: {order_id}"

order_id = OrderId(123)
user_id = UserId(123)

print(get_order(order_id))  ## Output: Order with ID: 123

Use o seguinte comando para executar o script.

python newtype.py

Verificação Estática de Tipos

Em Python, a verificação estática de tipos pode ser feita usando dicas de tipo (type hints) e um verificador estático de tipos como mypy. Dicas de tipo indicam os tipos esperados de variáveis, argumentos de função e valores de retorno. Aqui está um exemplo:

Primeiro, instale mypy.

pip install mypy

Aqui está um exemplo:

Crie um projeto chamado mypy.py no WebIDE e insira o seguinte conteúdo.

def add_numbers(x: int, y: int) -> int:
    return x + y

result = add_numbers(2, 3)
print(result)

Em seguida, execute mypy em seu script.

mypy mypy.py

Isso fornecerá feedback sobre quaisquer inconsistências de tipo encontradas em seu código.

Resumo

É isso! Agora você sabe como usar o módulo typing do Python para adicionar dicas de tipo (type hints) ao seu código. Dicas de tipo podem melhorar significativamente a legibilidade e a capacidade de manutenção do código, tornando mais fácil trabalhar com bases de código maiores e colaborar com outras pessoas.