Skip to content

Commit

Permalink
Merge pull request #497 from realpython/duck-typing-python
Browse files Browse the repository at this point in the history
Sample code for the Duck typing article
  • Loading branch information
KateFinegan authored Feb 23, 2024
2 parents d090c06 + c085423 commit a5d36c8
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 0 deletions.
3 changes: 3 additions & 0 deletions duck-typing-python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Duck Typing in Python: Writing Flexible and Decoupled Code

This folder provides the code examples for the Real Python tutorial [Duck Typing in Python: Writing Flexible and Decoupled Code](https://realpython.com/duck-typing-python/).
22 changes: 22 additions & 0 deletions duck-typing-python/birds_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Duck:
def swim(self):
print("The duck is swimming")

def fly(self):
print("The duck is flying")


class Swan:
def swim(self):
print("The swan is swimming")

def fly(self):
print("The swan is flying")


class Albatross:
def swim(self):
print("The albatross is swimming")

def fly(self):
print("The albatross is flying")
11 changes: 11 additions & 0 deletions duck-typing-python/birds_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Duck:
def fly(self):
print("The duck is flying")

def swim(self):
print("The duck is swimming")


class Pigeon:
def fly(self):
print("The pigeon is flying")
3 changes: 3 additions & 0 deletions duck-typing-python/file.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name,age,job
John,25,Engineer
Jane,22,Designer
12 changes: 12 additions & 0 deletions duck-typing-python/file.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"name": "John",
"age": 25,
"job": "Engineer"
},
{
"name": "Jane",
"age": 22,
"job": "Designer"
}
]
6 changes: 6 additions & 0 deletions duck-typing-python/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
John
25
Engineer
Jane
22
Designer
10 changes: 10 additions & 0 deletions duck-typing-python/iteration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
numbers = [1, 2, 3]
person = ("Jane", 25, "Python Dev")
letters = "abc"
ordinals = {"one": "first", "two": "second", "three": "third"}
even_digits = {2, 4, 6, 8}
collections = [numbers, person, letters, ordinals, even_digits]

for collection in collections:
for value in collection:
print(value)
5 changes: 5 additions & 0 deletions duck-typing-python/mean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from collections.abc import Collection


def mean(grades: Collection) -> float:
return sum(grades) / len(grades)
24 changes: 24 additions & 0 deletions duck-typing-python/queues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from collections import deque


class Queue:
def __init__(self):
self._elements = deque()

def enqueue(self, element):
self._elements.append(element)

def dequeue(self):
return self._elements.popleft()

def __iter__(self):
return iter(self._elements)

def __len__(self):
return len(self._elements)

def __reversed__(self):
return reversed(self._elements)

def __contains__(self, element):
return element in self._elements
37 changes: 37 additions & 0 deletions duck-typing-python/readers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import csv
import json
from itertools import batched # Python >= 3.12


class TextReader:
def __init__(self, filename):
self.filename = filename

def read(self):
with open(self.filename, encoding="utf-8") as file:
return [
{
"name": batch[0].strip(),
"age": batch[1].strip(),
"job": batch[2].strip(),
}
for batch in batched(file.readlines(), 3)
]


class CSVReader:
def __init__(self, filename):
self.filename = filename

def read(self):
with open(self.filename, encoding="utf-8", newline="") as file:
return list(csv.DictReader(file))


class JSONReader:
def __init__(self, filename):
self.filename = filename

def read(self):
with open(self.filename, encoding="utf-8") as file:
return json.load(file)
59 changes: 59 additions & 0 deletions duck-typing-python/shapes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from math import pi
from typing import Protocol


class Shape(Protocol):
def area(self) -> float:
...

def perimeter(self) -> float:
...


class Circle:
def __init__(self, radius: float) -> None:
self.radius = radius

def area(self) -> float:
return pi * self.radius**2

def perimeter(self) -> float:
return 2 * pi * self.radius


class Square:
def __init__(self, side: float) -> None:
self.side = side

def area(self) -> float:
return self.side**2

def perimeter(self) -> float:
return 4 * self.side


class Rectangle:
def __init__(self, length: float, width: float) -> None:
self.length = length
self.width = width

def area(self) -> float:
return self.length * self.width

def perimeter(self) -> float:
return 2 * (self.length + self.width)


def describe_shape(shape: Shape) -> None:
print(f"{type(shape).__name__}")
print(f" Area: {shape.area():.2f}")
print(f" Perimeter: {shape.perimeter():.2f}")


circle = Circle(3)
square = Square(5)
rectangle = Rectangle(4, 5)

describe_shape(circle)
describe_shape(square)
describe_shape(rectangle)
42 changes: 42 additions & 0 deletions duck-typing-python/vehicles_abc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from abc import ABC, abstractmethod


class Vehicle(ABC):
def __init__(self, make, model, color):
self.make = make
self.model = model
self.color = color

@abstractmethod
def start(self):
raise NotImplementedError("This method must be implemented")

@abstractmethod
def stop(self):
raise NotImplementedError("This method must be implemented")

@abstractmethod
def drive(self):
raise NotImplementedError("This method must be implemented")


class Car(Vehicle):
def start(self):
print("The car is starting")

def stop(self):
print("The car is stopping")

def drive(self):
print("The car is driving")


class Truck(Vehicle):
def start(self):
print("The truck is starting")

def stop(self):
print("The truck is stopping")

def drive(self):
print("The truck is driving")
30 changes: 30 additions & 0 deletions duck-typing-python/vehicles_duck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Car:
def __init__(self, make, model, color):
self.make = make
self.model = model
self.color = color

def start(self):
print("The car is starting")

def stop(self):
print("The car is stopping")

def drive(self):
print("The car is driving")


class Truck:
def __init__(self, make, model, color):
self.make = make
self.model = model
self.color = color

def start(self):
print("The truck is starting")

def stop(self):
print("The truck is stopping")

def drive(self):
print("The truck is driving")

0 comments on commit a5d36c8

Please sign in to comment.