-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #549 from realpython/python-protocol
Sample code for the article on Python protocols
- Loading branch information
Showing
22 changed files
with
509 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Python Protocols: Leveraging Structural Subtyping | ||
|
||
This folder provides the code examples for the Real Python tutorial [Python Protocols: Leveraging Structural Subtyping](https://realpython.com/python-protocol/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from typing import Protocol | ||
|
||
|
||
class Adder(Protocol): | ||
def add(self, x, y): ... | ||
|
||
|
||
class IntAdder: | ||
def add(self, x, y): | ||
return x + y | ||
|
||
|
||
class FloatAdder: | ||
def add(self, x, y): | ||
return x + y | ||
|
||
|
||
def add(adder: Adder) -> None: | ||
print(adder.add(2, 3)) | ||
|
||
|
||
add(IntAdder()) | ||
add(FloatAdder()) | ||
|
||
|
||
for adder in [IntAdder(), FloatAdder()]: | ||
add(adder) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from typing import Protocol | ||
|
||
|
||
class Adder(Protocol): | ||
def add(self, x: float, y: float) -> float: ... | ||
|
||
|
||
class IntAdder: | ||
def add(self, x: int, y: int) -> int: | ||
return x + y | ||
|
||
|
||
def add(adder: Adder) -> None: | ||
print(adder.add(2, 3)) | ||
|
||
|
||
# add(IntAdder()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from typing import Protocol | ||
|
||
|
||
class Adder(Protocol): | ||
def add(self, x: int | float, y: int | float) -> int | float: ... | ||
|
||
|
||
class IntAdder: | ||
def add(self, x: int, y: int) -> int: | ||
return x + y | ||
|
||
|
||
def add(adder: Adder) -> None: | ||
print(adder.add(2, 3)) | ||
|
||
|
||
# add(IntAdder()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from typing import Protocol, TypeVar | ||
|
||
T = TypeVar("T", bound=int | float) | ||
|
||
|
||
class Adder(Protocol[T]): | ||
def add(self, x: T, y: T) -> T: ... | ||
|
||
|
||
class IntAdder: | ||
def add(self, x: int, y: int) -> int: | ||
return x + y | ||
|
||
|
||
class FloatAdder: | ||
def add(self, x: float, y: float) -> float: | ||
return x + y | ||
|
||
|
||
def add(adder: Adder) -> None: | ||
print(adder.add(2, 3)) | ||
|
||
|
||
add(IntAdder()) | ||
add(FloatAdder()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from typing import Protocol | ||
|
||
|
||
class Adder(Protocol): | ||
def add[T: int | float | str](self, x: T, y: T) -> T: ... | ||
|
||
|
||
class IntAdder: | ||
def add(self, x: int, y: int) -> int: | ||
return x + y | ||
|
||
|
||
class FloatAdder: | ||
def add(self, x: float, y: float) -> float: | ||
return x + y | ||
|
||
|
||
def add(adder: Adder) -> None: | ||
print(adder.add(2, 3)) | ||
|
||
|
||
add(IntAdder()) | ||
add(FloatAdder()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from typing import Protocol | ||
|
||
|
||
class Adder(Protocol): | ||
def add[T: int | float | str](self, x: T, y: T) -> T: ... | ||
|
||
|
||
class IntAdder: | ||
def add(self, x: int, y: int) -> int: | ||
return x + y | ||
|
||
|
||
class FloatAdder: | ||
def add(self, x: float, y: float) -> float: | ||
return x + y | ||
|
||
|
||
class StrAdder: | ||
def add(self, x: str, y: str) -> str: | ||
return x + y | ||
|
||
|
||
def add(adder: Adder) -> None: | ||
print(adder.add(2, 3)) | ||
|
||
|
||
add(IntAdder()) | ||
add(FloatAdder()) | ||
add(StrAdder()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
class Animal: | ||
def __init__(self, name): | ||
self.name = name | ||
|
||
def eat(self): | ||
print(f"{self.name} is eating.") | ||
|
||
def drink(self): | ||
print(f"{self.name} is drinking.") | ||
|
||
|
||
class Dog(Animal): | ||
def bark(self): | ||
print(f"{self.name} is barking.") | ||
|
||
|
||
class Cat(Animal): | ||
def meow(self): | ||
print(f"{self.name} is meowing.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
class Dog: | ||
def __init__(self, name): | ||
self.name = name | ||
|
||
def eat(self): | ||
print(f"{self.name} is eating.") | ||
|
||
def drink(self): | ||
print(f"{self.name} is drinking.") | ||
|
||
def make_sound(self): | ||
print(f"{self.name} is barking.") | ||
|
||
|
||
class Cat: | ||
def __init__(self, name): | ||
self.name = name | ||
|
||
def eat(self): | ||
print(f"{self.name} is eating.") | ||
|
||
def drink(self): | ||
print(f"{self.name} is drinking.") | ||
|
||
def make_sound(self): | ||
print(f"{self.name} is meowing.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
class Duck: | ||
def quack(self): | ||
return "The duck is quacking!" | ||
|
||
|
||
def make_it_quack(duck: Duck) -> str: | ||
return duck.quack() | ||
|
||
|
||
class Person: | ||
def quack(self): | ||
return "The person is imitating a duck quacking!" | ||
|
||
|
||
print(make_it_quack(Duck())) | ||
# print(make_it_quack(Person())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
class QuackingThing: | ||
def quack(self): | ||
raise NotImplementedError("Subclasses must implement this method") | ||
|
||
|
||
class Duck(QuackingThing): | ||
def quack(self): | ||
return "The duck is quacking!" | ||
|
||
|
||
class Person(QuackingThing): | ||
def quack(self): | ||
return "The person is imitating a duck quacking!" | ||
|
||
|
||
def make_it_quack(duck: QuackingThing) -> str: | ||
return duck.quack() | ||
|
||
|
||
print(make_it_quack(Duck())) | ||
print(make_it_quack(Person())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from typing import Union | ||
|
||
|
||
def add(a: Union[float, int], b: Union[float, int]) -> float: | ||
return float(a + b) | ||
|
||
|
||
print(add(2, 4)) | ||
# print(add("2", "4")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
from typing import Protocol | ||
|
||
|
||
class ContentCreator(Protocol): | ||
def create_content(self) -> str: ... | ||
|
||
|
||
class Blogger(ContentCreator, Protocol): | ||
posts: list[str] | ||
|
||
def add_post(self, title: str, content: str) -> None: ... | ||
|
||
|
||
class Vlogger(ContentCreator, Protocol): | ||
videos: list[str] | ||
|
||
def add_video(self, title: str, path: str) -> None: ... | ||
|
||
|
||
class Blog: | ||
def __init__(self): | ||
self.blog_posts = [] | ||
|
||
def create_content(self) -> str: | ||
return "Creating a post." | ||
|
||
def add_post(self, title: str, content: str) -> None: | ||
self.blog_posts.append(f"{title}: {content}") | ||
print(f"Post added: {title}") | ||
|
||
|
||
class Vlog: | ||
def __init__(self): | ||
self.videos = [] | ||
|
||
def create_content(self) -> str: | ||
return "Recording a video." | ||
|
||
def add_video(self, title: str, path: str) -> None: | ||
self.videos.append(f"{title}: {path}") | ||
print(f"Video added: {title}") | ||
|
||
|
||
def produce_content(creator: ContentCreator): | ||
print(creator.create_content()) | ||
|
||
|
||
def add_post(blogger: Blogger, title: str, content: str): | ||
blogger.add_post(title, content) | ||
|
||
|
||
def add_video(vlogger: Vlogger, title: str, path: str): | ||
vlogger.add_video(title, path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
def filter_even_numbers(numbers): | ||
return [number for number in numbers if number % 2 == 0] | ||
|
||
|
||
print(filter_even_numbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) | ||
print(filter_even_numbers((1, 2, 3, 4, 5, 6, 7, 8, 9, 10))) | ||
print(filter_even_numbers({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
def filter_even_numbers(numbers: list[int]) -> list[int]: | ||
return [number for number in numbers if number % 2 == 0] | ||
|
||
|
||
print(filter_even_numbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) | ||
# print(filter_even_numbers((1, 2, 3, 4, 5, 6, 7, 8, 9, 10))) | ||
# print(filter_even_numbers({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from collections.abc import Iterable | ||
|
||
|
||
def filter_even_numbers(numbers: Iterable[int]) -> list[int]: | ||
return [number for number in numbers if number % 2 == 0] | ||
|
||
|
||
print(filter_even_numbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) | ||
print(filter_even_numbers((1, 2, 3, 4, 5, 6, 7, 8, 9, 10))) | ||
print(filter_even_numbers({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from typing import Optional, Protocol | ||
|
||
|
||
class LinkedListNode(Protocol): | ||
value: int | ||
next_node: Optional["LinkedListNode"] | ||
|
||
def __str__(self) -> str: | ||
return f"{self.value} -> {self.next_node}" | ||
|
||
|
||
class Node: | ||
def __init__( | ||
self, | ||
value: int, | ||
next_node: Optional["LinkedListNode"] = None, | ||
): | ||
self.value = value | ||
self.next_node = next_node | ||
|
||
def __str__(self) -> str: | ||
return f"{self.value} -> {self.next_node}" | ||
|
||
|
||
def print_linked_list(start_node: LinkedListNode): | ||
print(start_node) | ||
|
||
|
||
node3 = Node(3) | ||
node2 = Node(2, node3) | ||
node1 = Node(1, node2) | ||
|
||
print_linked_list(node1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from abc import abstractmethod | ||
from typing import ClassVar, Protocol | ||
|
||
|
||
class ProtocolMembersDemo(Protocol): | ||
class_attribute: ClassVar[int] | ||
instance_attribute: str | ||
|
||
def instance_method(self, arg: int) -> str: ... | ||
|
||
@classmethod | ||
def class_method(cls) -> str: ... | ||
|
||
@staticmethod | ||
def static_method(arg: int) -> str: ... | ||
|
||
@property | ||
def property_name(self) -> str: ... | ||
|
||
@property_name.setter | ||
def property_name(self, value: str) -> None: ... | ||
|
||
@abstractmethod | ||
def abstract_method(self) -> str: ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
class Person: | ||
def __init__(self, name): | ||
self.name = name | ||
|
||
def eat(self): | ||
print(f"{self.name} is eating.") | ||
|
||
def drink(self): | ||
print(f"{self.name} is drinking.") | ||
|
||
def talk(self): | ||
print(f"{self.name} is talking.") |
Oops, something went wrong.