"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Duck Typing atende dicas de tipo: usando protocolos em Python

Duck Typing atende dicas de tipo: usando protocolos em Python

Publicado em 2024-09-04
Navegar:495

Duck Typing Meets Type Hints: Using Protocols in Python

A natureza dinâmica do Python e o suporte para digitação de pato são elogiados há muito tempo por sua flexibilidade. No entanto, à medida que as bases de código ficam maiores e mais complexas, os benefícios da verificação de tipo estático tornam-se cada vez mais aparentes. Mas como podemos conciliar a flexibilidade da digitação com pato com a segurança da verificação estática de tipos? Entre na classe Protocolo do Python.

Neste tutorial, você aprenderá:

  1. O que é digitação duck e como ela é suportada em Python
  2. Os prós e contras da digitação com pato
  3. Como as classes base abstratas (ABCs) tentam resolver problemas de digitação
  4. Como usar o protocolo para obter o melhor dos dois mundos: flexibilidade de digitação com verificação de tipo estático

Compreendendo a digitação de pato

Duck Typing é um conceito de programação em que o tipo ou classe de um objeto é menos importante do que os métodos que ele define. É baseado na ideia de que "Se parece um pato, nada como um pato e grasna como um pato, então provavelmente é um pato."

Em Python, a digitação duck é totalmente suportada. Por exemplo:

class Duck:
    def quack(self):
        print("Quack!")

class Person:
    def quack(self):
        print("I'm imitating a duck!")

def make_it_quack(thing):  # Note: No type hint here
    thing.quack()

duck = Duck()
person = Person()

make_it_quack(duck)    # Output: Quack!
make_it_quack(person)  # Output: I'm imitating a duck!

Neste exemplo, make_it_quack não se importa com o tipo de coisa. Só importa que essa coisa tenha um método charlatão. Observe que não há dica de tipo para o parâmetro thing, o que é típico em código digitado em pato, mas pode levar a problemas em bases de código maiores.

Prós e contras da digitação de pato

A digitação Duck oferece diversas vantagens:

  1. Flexibilidade: permite um código mais flexível que não está vinculado a tipos específicos.
  2. Reutilização de código mais fácil: você pode usar classes existentes em novos contextos sem modificação.
  3. Ênfase no comportamento: concentra-se no que um objeto pode fazer, e não no que ele é.

No entanto, também tem algumas desvantagens:

  1. Falta de clareza: pode não estar claro quais métodos um objeto precisa implementar.
  2. Erros de tempo de execução: erros relacionados ao tipo são detectados apenas em tempo de execução.
  3. Menos suporte IDE: os IDEs lutam para fornecer preenchimento automático preciso e verificação de erros.

A solução ABC

Uma abordagem para resolver esses problemas é usar Abstract Base Classes (ABCs). Aqui está um exemplo:

from abc import ABC, abstractmethod

class Quacker(ABC):
    @abstractmethod
    def quack(self):
        pass

class Duck(Quacker):
    def quack(self):
        print("Quack!")

class Person(Quacker):
    def quack(self):
        print("I'm imitating a duck!")

def make_it_quack(thing: Quacker):
    thing.quack()

duck = Duck()
person = Person()

make_it_quack(duck)
make_it_quack(person)

Embora essa abordagem forneça melhor verificação de tipo e interfaces mais claras, ela tem desvantagens:

  1. Requer herança, o que pode levar a hierarquias inflexíveis.
  2. Não funciona com classes existentes que você não pode modificar.
  3. Isso vai contra a filosofia de "digitação de pato" do Python.

Protocolos: o melhor dos dois mundos

Python 3.8 introduziu a classe Protocol, que nos permite definir interfaces sem exigir herança. Veja como podemos usá-lo:

from typing import Protocol

class Quacker(Protocol):
    def quack(self):...

class Duck:
    def quack(self):
        print("Quack!")

class Person:
    def quack(self):
        print("I'm imitating a duck!")

def make_it_quack(thing: Quacker):
    thing.quack()

duck = Duck()
person = Person()

make_it_quack(duck)
make_it_quack(person)

Vamos detalhar isso:

  1. Definimos um protocolo Quacker que especifica a interface que esperamos.
  2. Nossas classes Duck e Person não precisam herdar de nada.
  3. Podemos usar dicas de tipo com make_it_quack para especificar que ele espera um Quacker.

Essa abordagem nos oferece vários benefícios:

  1. Verificação de tipo estático: IDEs e verificadores de tipo podem detectar erros antes do tempo de execução.
  2. Não é necessária herança: as classes existentes funcionam desde que tenham os métodos corretos.
  3. Interfaces claras: o protocolo define claramente quais métodos são esperados.

Aqui está um exemplo mais complexo mostrando como os protocolos podem ser tão complexos quanto necessário (Forma), mantendo suas classes de domínio (Círculo, Retângulo) planas:

from typing import Protocol, List

class Drawable(Protocol):
    def draw(self): ...

class Resizable(Protocol):
    def resize(self, factor: float): ...

class Shape(Drawable, Resizable, Protocol):
    pass

def process_shapes(shapes: List[Shape]):
    for shape in shapes:
        shape.draw()
        shape.resize(2.0)

# Example usage
class Circle:
    def draw(self):
        print("Drawing a circle")

    def resize(self, factor: float):
        print(f"Resizing circle by factor {factor}")

class Rectangle:
    def draw(self):
        print("Drawing a rectangle")

    def resize(self, factor: float):
        print(f"Resizing rectangle by factor {factor}")

# This works with any class that has draw and resize methods,
# regardless of its actual type or inheritance
shapes: List[Shape] = [Circle(), Rectangle()]
process_shapes(shapes)

Neste exemplo, Circle e Rectangle não herdam de Shape ou de qualquer outra classe. Eles simplesmente implementam os métodos necessários (desenhar e redimensionar). A função process_shapes pode funcionar com qualquer objeto que possua esses métodos, graças ao protocolo Shape.

Resumo

Os protocolos em Python fornecem uma maneira poderosa de trazer digitação estática para código digitado em pato. Eles nos permitem especificar interfaces no sistema de tipos sem exigir herança, mantendo a flexibilidade da digitação duck e ao mesmo tempo adicionando os benefícios da verificação estática de tipos,

Ao usar protocolos, você pode:

  1. Defina interfaces claras para seu código
  2. Obtenha um IDE melhor, (verificação de tipo estático), suporte e detecte erros mais cedo
  3. Mantenha a flexibilidade da digitação do pato
  4. Aproveite a verificação de tipo para classes que você não consegue modificar.

Se você quiser saber mais sobre protocolos e dicas de tipo em Python, verifique a documentação oficial do Python no módulo de digitação ou explore ferramentas avançadas de verificação de tipo estático como mypy.

Boa codificação e que seus patos sempre grasnam com segurança de tipo!

Você pode encontrar mais do meu conteúdo, incluindo meu boletim informativo aqui

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/samkeen/duck-typing-meets-type-hints-using-protocols-in-python-4d8l?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3