Skip to content

Instantly share code, notes, and snippets.

@mahenzon
Created February 2, 2025 11:57
Show Gist options
  • Save mahenzon/693b70c665674854f87f1a31e96e9d14 to your computer and use it in GitHub Desktop.
Save mahenzon/693b70c665674854f87f1a31e96e9d14 to your computer and use it in GitHub Desktop.
Protocol annotation in Python
from typing import Protocol
class MessageCallback(Protocol):
__name__: str
def __call__(
self,
message: str,
size: int,
) -> None: ...
def process_incoming_message(
data: bytes,
callback: MessageCallback,
) -> None:
message = data.decode("utf-8")
message_size = len(message)
print("Notify callback", callback.__name__)
callback(
message,
message_size,
)
callback(
message=message,
size=message_size,
)
callback(
message,
size=message_size,
)
def my_callback(
message: str,
size: int,
extra: dict[str, str] | None = None,
) -> None:
print("received", repr(message), "of size", size)
def main() -> None:
data = b"Hello World!"
process_incoming_message(
data=data,
callback=my_callback,
)
if __name__ == "__main__":
main()
from typing import Protocol
FILE_PATH = "/Users/suren/MyFiles/suren/videos/062.protocol-type/my-file.txt"
class Readable(Protocol):
def read(self) -> bytes: ...
class FileReader:
def __init__(self, filename: str) -> None:
self.filename = filename
def read(self) -> bytes:
"""
Вычитываем файл и возвращаем содержимое файла
"""
print("read data from filereader", self.filename)
# просто какие-то байты
return self.filename.encode()
class APIReader(Readable):
def __init__(self, api_path: str) -> None:
self.api_path = api_path
def read(self) -> bytes:
"""
Делаем API запрос и возвращаем байты
"""
print("read data from API", self.api_path)
# имитация
return self.api_path.encode()
def read_and_save_to_db(readable: Readable) -> None:
print("+ save to db:", readable.read())
def main() -> None:
file_reader = FileReader("example-file.txt")
api_reader = APIReader("example/api/path")
# print(file_reader.read())
# print(api_reader.read())
read_and_save_to_db(file_reader)
read_and_save_to_db(api_reader)
print()
file = open(FILE_PATH, "rb")
read_and_save_to_db(file)
# reveal_type(file.read)
if __name__ == "__main__":
main()
import math
from typing import Protocol, runtime_checkable
@runtime_checkable
class Shape(Protocol):
def area(self) -> float: ...
def perimeter(self) -> str: ...
class Circle:
def __init__(self, radius: float) -> None:
self.radius = radius
self.family = "circle"
def area(self) -> float:
return math.pi * self.radius**2
def perimeter(self) -> float:
return 2 * math.pi * self.radius
circumference = perimeter
class Rectangle:
def __init__(self, width: float, height: float) -> None:
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
def print_shape_info(shape: Shape) -> None:
print("Shape area", shape.area())
print("Shape perimeter()", shape.perimeter())
def main() -> None:
circle = Circle(5)
print("Circle perimeter", circle.perimeter())
print("Circle circumference", circle.circumference())
rectangle = Rectangle(5, 7)
# print_shape_info(circle)
# print_shape_info(rectangle)
for elem in [circle, rectangle, "foobar"]:
if isinstance(elem, Shape):
print(f"{elem.__class__.__name__} is a Shape")
print_shape_info(elem)
else:
print(f"Element type {type(elem)} is not a Shape")
if __name__ == "__main__":
main()
[tool.mypy]
strict = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment