Python

Write an awesome doc for Python. A very nice an practical one extracted from Python official documentation.

View on GitHub

Inheritance

Why do we need inheritance?

from typing import Literal


# Superclass: Bird
class Bird:
    def __init__(
            self, name: str,
            beak: Literal["short", "medium", "long"],
            wing_length: int) -> None:
        self.name = name
        self.beak = beak
        self.wing_length = wing_length

    def eat(self) -> str:
        return f"{self.name} is eating."


# Subclass: FlyingBird (inherits from Bird)
class FlyingBird(Bird):
    def fly(self) -> None:
        print(f"{self.name} is flying.")


# Subclass: Eagle (inherits from FlyingBird)
class Eagle(FlyingBird):
    def prey(self, prey_name: str) -> None:
        self.prey_name = prey_name
        print(f"{self.name} preys on a {prey_name}!")

    def eat(self) -> str:
        if not hasattr(self, 'prey_name'):
            return "No prey found. Cannot eat."

        msg = super().eat()
        msg += f" It's meal is a ${self.prey_name}"

        return msg


# Subclass: FlightlessBird (inherits from Bird)
class FlightlessBird(Bird):
    pass


# Subclass: Ostrich (inherits from FlightlessBird)
class Ostrich(FlightlessBird):
    def run(self) -> None:
        print(f"{self.name} runs!")


# Subclass: Penguin (inherits from FlightlessBird)
class Penguin(FlightlessBird):
    def swim(self) -> None:
        print(f"{self.name} swims!")


# Example usage
if __name__ == "__main__":
    eagle = Eagle("Bald Eagle", "medium", 100)
    ostrich = Ostrich("African Ostrich", "short", 50)
    penguin = Penguin("Emperor Penguin", "medium", 20)

    eagle.fly()
    eagle.prey("rabbit")
    print(eagle.eat())

    ostrich.run()
    print(ostrich.eat())

    penguin.swim()
    print(penguin.eat())

[!NOTE]

In Python 3 a class with no super class actually inherits from object class. In other words these two codes are equivalent: | Implicit inheritance | Explicit inheritance | | — | — | | <pre lang="python">class MyClass:</pre> | <pre lang="python">class MyClass(object):</pre> |

Encapsulation

Polymorphism

Many forms

class Penguin:

    def swim(self) -> None:
        print("Penguins can swim, so I am swimming.")

    def walk(self) -> None:
        print("Penguins can walk, so I am walking.")

class Duck:

    def swim(self) -> None:
        print("Ducks can swim, so I am swimming.")

    def walk(self) -> None:
        print("Ducks can walk, so I am walking.")

sea_land_birds = [Penguin(), Duck()]

for bird in sea_land_birds:
    bird.swim()
    bird.walk()

Duck test

[!TIP]

To fix the mypy red squigiline error, You can use a structrual type hint called Protocol:

from typing import Protocol
# ...
class SeaLandBird(Protocol):
    def swim(self) -> None: ...
    def walk(self) -> None: ...
# ...
sea_land_birds: list[SeaLandBird] = [Penguin(), Duck()]

This is a way to define type compatibility based on the structure (methods/attributes) of an object, rather than its explicit class hierarchy (nominal typing). And what we’ve done abow is what’s know as “duck typing”.

Abstraction

Abstraction

from abc import ABC, abstractmethod


class Animal(ABC):
    """ Abstract base class for animals """

    def __init__(self, name):
        self.name = name

    @abstractmethod
    def make_sound(self):
        """ Abstract method to making a sound based on the animal type """
        pass

    def sleep(self):
        print(f"{self.name} is sleeping")


class Dog(Animal):
    def make_sound(self):
        print(f"{self.name} says Woof!")


class Cat(Animal):
    def make_sound(self):
        print(f"{self.name} says Meow!")


if __name__ == "__main__":
    shepherd_dog = Dog("max")
    whiskers = Cat("Whiskers")

    shepherd_dog.make_sound()
    whiskers.make_sound()
    shepherd_dog.sleep()

    # This would raise an error since Animal is abstract
    # animal = Animal("Generic")

YouTube/Aparat