Resumo : neste tutorial, você aprenderá sobre o protocolo Python e seu uso para definir interfaces implícitas.
Introdução ao protocolo Python
Suponha que você tenha uma função que calcula o valor total de uma lista de produtos, onde cada produto possui os atributos nome, quantidade e preço:
from typing import List
class Product:
def __init__(self, name: str, quantity: float, price: float):
self.name = name
self.quantity = quantity
self.price = price
def calculate_total(items: List[Product]) -> float:
return sum([item.quantity * item.price for item in items])
Linguagem de código: Python ( python )
Neste exemplo, a calculate_total()
função aceita uma lista de Product
objetos e retorna o valor total.
Ao escrever esta função, você pode querer calcular o total de uma lista de produtos. Mas você provavelmente desejará usá-lo para outras listas, como listas de inventário, no futuro.
Se você observar atentamente a calculate_total()
função, ela usa apenas os atributos de quantidade e preço.
Para tornar o calcula_total() mais dinâmico enquanto aproveita as dicas de tipo , você pode usar o Protocol
do typing
módulo. A classe Protocol está disponível desde Python 3.8, descrita no PEP 544 .
O seguinte descreve como usar a Protocol
classe.
Primeiro, defina uma Item
classe que herda de Protocol
com dois atributos: quantidade e preço:
class Item(Protocol):
quantity: float
price: float
Linguagem de código: Python ( python )
Segundo, altere a calculate_total()
função que aceita uma lista de Item
objetos em vez de uma lista de Product
objetos:
def calculate_total(items: List[Item]) -> float:
return sum([item.quantity * item.price for item in items])
Linguagem de código: Python ( python )
Ao fazer isso, você pode passar qualquer lista de Item
objetos para a calculate_total()
função com a condição de que cada item tenha dois atributos quantidade e preço.
O seguinte mostra um programa completo:
from typing import List, Protocol
class Item(Protocol):
quantity: float
price: float
class Product:
def __init__(self, name: str, quantity: float, price: float):
self.name = name
self.quantity = quantity
self.price = price
def calculate_total(items: List[Item]) -> float:
return sum([item.quantity * item.price for item in items])
# calculate total a product list
total = calculate_total([
Product('A', 10, 150),
Product('B', 5, 250)
])
print(total)
Linguagem de código: Python ( python )
Por exemplo, você pode definir uma lista de estoques em estoque e passá-los para a calculate_total()
função:
# ...
class Stock:
def __init__(self, product_name, quantity, price):
self.product_name = product_name
self.quantity = quantity
self.price = price
# calculate total an inventory list
total = calculate_total([
Stock('Tablet', 5, 950),
Stock('Laptop', 10, 850)
])
print(total)
Linguagem de código: Python ( python )
Neste exemplo, a classe Product
e Stock
não precisa ser uma subclasse da Item
classe, mas ainda pode ser usada na calculate_total()
função.
Isso é chamado de digitação de pato em Python. Na digitação duck, os comportamentos e propriedades de um objeto determinam o tipo do objeto, não o tipo explícito do objeto.
Por exemplo, um objeto com quantidade e preço seguirá o Item
protocolo, independente de seu tipo explícito.
A digitação do pato é inspirada no teste do pato:
Se ele anda como um pato e grasna como um pato, então deve ser um pato.
Na prática, quando você escreve uma função que aceita entrada, você se preocupa mais com os comportamentos e propriedades da entrada, não com seu tipo explícito.
Resumo
- Use o protocolo Python para definir interfaces implícitas.