Skip to content

Instantly share code, notes, and snippets.

@atemate
Last active June 4, 2024 16:41
Show Gist options
  • Save atemate/fc828014f86d1d2feb4f19f3c9e8bb66 to your computer and use it in GitHub Desktop.
Save atemate/fc828014f86d1d2feb4f19f3c9e8bb66 to your computer and use it in GitHub Desktop.
Python OOP
>>> from os import PathLike
>>> class MyPath(PathLike):
...     def __init__(self, prefix, path):
...         self._prefix = prefix
...         self._path = path
...
...     def __fspath__(self):
...         return self._prefix + self._path
...
>>>
>>> from pathlib import Path
>>> os.fspath(Path("test.txt"))
'test.txt'
>>> os.fspath(MyPath("https://", "test.txt"))
'https://test.txt'

Normal "minimal" usage

>>> class Animal:
...     def _say(self):
...         pass
...     def speak(self):
...         return f"I am an animal that says '{self._say()}'"
...
>>> class Cat(Animal):
...     def _say(self):
...         return "meow"
...
>>> class Dog(Animal):
...     def _say(self):
...         return "woof!"
...
>>> d = Dog()
>>> d.speak()
"I am an animal that says 'woof!'"
>>> c = Cat()
>>> c.speak()
"I am an animal that says 'meow'"

So we're having a common abstraction Animal with some common functionality speak(), which internally uses an "abstract" method _say() that defines specific narrow functionality of a child concrete class (Dog and Cat).

From the OOP high-level perspective, Animal is an abstract class, it's its function that it serves to its children classes.

Normally, abstract classes should not be instantiated (i.e. there can't exist an "animal", but only a "dog" or a "cat") as the program doesn't have enough information about how the instances should behave (i.e. what should _say() an animal, meow or bark?).

However, Python does not restrict us from doing so:

>>> a.get_sentence()
"I am an animal that says 'None'"

So usually we're creating abstract classes using the library abc:

>>> class Animal(abc.ABC):
...     @abc.abstractmethod
...     def _say(self):
...         pass
...     def get_sentence(self):
...         return f"I am an animal that says '{self._say()}'"
...
>>> a = Animal()
Traceback (most recent call last):
  Cell In[20], line 1
    a = Animal()
TypeError: Can't instantiate abstract class Animal with abstract method _say

>>> class Dog(Animal):
...     pass
...
>>> d = Dog()
Traceback (most recent call last):
  Cell In[22], line 1
    d = Dog()
TypeError: Can't instantiate abstract class Dog with abstract method _say

Often, instead of @abc.abstractmethod we're throwing an exception raise NotImplementedError("implement me") in the abstract method:

>>> class Animal:
...     def _say(self):
...         raise NotImplementedError("_say()")
...     def speak(self):
...         return f"I am an animal that says '{self._say()}'"
...
... class Cat(Animal):
...     def _say(self):
...         return "meow"
...
... class Dog(Animal):
...     def _say(self):
...         return "woof!"
...
>>> Animal().speak()
Traceback (most recent call last):
  ...
NotImplementedError: _say()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment