Protocolo Python

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 Productobjetos 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 Protocoldo typingmódulo. A classe Protocol está disponível desde Python 3.8, descrita no PEP 544 .

O seguinte descreve como usar a Protocolclasse.

Primeiro, defina uma Itemclasse que herda de Protocolcom dois atributos: quantidade e preço:

class Item(Protocol):
    quantity: float
    price: floatLinguagem de código:  Python  ( python )

Segundo, altere a calculate_total()função que aceita uma lista de Itemobjetos em vez de uma lista de Productobjetos:

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 Itemobjetos 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 Producte Stocknão precisa ser uma subclasse da Itemclasse, 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 Itemprotocolo, 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.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *