Динамичность Python и поддержка утиной печати уже давно хвалят за гибкость. Однако по мере того, как кодовые базы становятся больше и сложнее, преимущества статической проверки типов становятся все более очевидными. Но как мы можем совместить гибкость утиной типизации с безопасностью статической проверки типов? Введите класс протокола Python.
Из этого урока вы узнаете:
Утиная типизация — это концепция программирования, в которой тип или класс объекта менее важен, чем определяемые им методы. Он основан на идее: «Если что-то выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это и есть утка».
В Python полностью поддерживается утиная типизация. Например:
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!
В этом примере make_it_quack не заботится о типе объекта. Его волнует только то, что у этой штуки шарлатанский метод. Обратите внимание, что для параметраthing нет подсказки типа, что типично для кода с утиной типизацией, но может привести к проблемам в более крупных базах кода.
Утиный набор текста дает ряд преимуществ:
Однако у него есть и недостатки:
Один из подходов к решению этих проблем — использование абстрактных базовых классов (ABC). Вот пример:
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)
Хотя этот подход обеспечивает лучшую проверку типов и более понятный интерфейс, у него есть недостатки:
В Python 3.8 появился класс протокола, который позволяет нам определять интерфейсы без необходимости наследования. Вот как мы можем его использовать:
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)
Давайте разберемся:
Этот подход дает нам несколько преимуществ:
Вот более сложный пример, показывающий, как протоколы могут быть настолько сложными, насколько это необходимо (форма), сохраняя при этом классы предметной области (круг, прямоугольник) плоскими:
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)
В этом примере Circle и Rectangle не наследуются от Shape или любого другого класса. Они просто реализуют необходимые методы (рисование и изменение размера). Функцияprocess_shapes может работать с любыми объектами, имеющими эти методы, благодаря протоколу Shape.
Протоколы Python предоставляют мощный способ реализовать статическую типизацию в коде с утиной типизацией. Они позволяют нам указывать интерфейсы в системе типов, не требуя наследования, сохраняя гибкость утиной типизации и добавляя преимущества статической проверки типов,
Используя протоколы, вы можете:
Если вы хотите узнать больше о протоколах и подсказках типов в Python, ознакомьтесь с официальной документацией Python по модулю типизации или изучите расширенные инструменты статической проверки типов, такие как mypy.
Удачного программирования, и пусть ваши утки всегда крякают о безопасности типов!
Вы можете найти больше моего контента, включая мою рассылку, здесь
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3