Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Abstract Base Classes

Abstract Base Classes

A review of Abstract Base Classes in Python.
Themes: Polymorphism, behaviours and delegation, collection, registering, Abstract Base Classes, categories, metaclasses, interfaces

Leonardo Giordani

April 15, 2016
Tweet

More Decks by Leonardo Giordani

Other Decks in Programming

Transcript

  1. Abstract Base Classes
    A smart use of metaclasses in Python
    LEonardo GIordani @LGiordani
    http://thedigitalcatonline.com

    View Slide

  2. Abstract Base Classes – LEonardo GIordani - @LGiordani
    About Me
    Born in 1977 with Star Wars, bash, Apple ][, BSD, finger, Zork, Galaxy Express 999, Little
    Pollon, Dire Straits, The Police, Rumours, The Silmarillion, Squad Leader.
    Interested in operating systems and computer languages, photography, fantasy and science
    fiction, video- and boardgames, guitar playing, climbing, horseback riding, Aikido, rollerskating,
    drawing, painting, bookbinding.
    I programmed in Z80 and x86 Assembly, GW-Basic, Logo, Borland Turbo Pascal, Prolog, C,
    C++, PHP, Lisp, Ada, Objective-C, bash, Python, Erlang, Clojure, Scala, JavaScript.
    I love mathematics and cryptography.
    tl; dr
    me = nerd + coder

    View Slide

  3. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Overview
    Level 1
    Level 2
    Polymorphism - Behaviours and delegation - Collections
    Registering - Abstract Base Classes - Categories
    Level 3
    Build your ABCs - Metaclasses - ABCs as interfaces

    View Slide

  4. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Level 1

    View Slide

  5. Abstract Base Classes – LEonardo GIordani - @LGiordani
    OOP: behaviour over structure

    View Slide

  6. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Python EAFP
    Test the behaviour, not the structure
    try:
    someobj[1]
    except TypeError:
    # object is not subscriptable
    ...

    View Slide

  7. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Example of behaviour
    class ListView(View):
    def status(self):
    ...
    class ItemView(View):
    def status(self):
    ...

    View Slide

  8. Abstract Base Classes – LEonardo GIordani - @LGiordani
    How to check how an object behaves?
    try:
    someobj.status
    except AttributeError:
    ...

    View Slide

  9. Abstract Base Classes – LEonardo GIordani - @LGiordani
    How to check if something behaves like a list?
    try:
    someobj.append
    someobj.extend
    someobj.index
    except AttributeError:
    ...
    This is checking the structure: wrong

    View Slide

  10. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Temptation
    if isinstance(someobj, list):
    ...
    This is checking the type: wrong

    View Slide

  11. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Temptation - Part 2
    if isinstance(someobj, list) or \
    isinstance(someobj, tuple) or \
    isinstance(someobj, str):
    ...
    And quickly becomes unmaintainable

    View Slide

  12. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Perfect solution
    if behaveslike(someobj, ListBehaviour):
    ...

    View Slide

  13. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Python is based on delegation

    View Slide

  14. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Original version of isinstance()*
    def isinstance(obj, _class):
    return _class in obj.__class__.__bases__
    *simplified version

    View Slide

  15. Abstract Base Classes – LEonardo GIordani - @LGiordani
    New version of isinstance()*
    def isinstance(obj, _class):
    return _class.__instancecheck__(obj)
    *simplified version

    View Slide

  16. Abstract Base Classes – LEonardo GIordani - @LGiordani
    This is now possible
    if isinstance(someobj, ListBehaviour):
    ...
    We just need to implement “behaviour” classes

    View Slide

  17. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Collections
    classes that represent interesting behaviours
    >>> import collections
    >>>
    >>> isinstance(“a string”, collections.Sequence)
    True
    >>>
    >>> isinstance(“a string”, collections.Mapping)
    False
    >>>
    https://docs.python.org/3/library/collections.abc.html

    View Slide

  18. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Level 2

    View Slide

  19. Abstract Base Classes – LEonardo GIordani - @LGiordani
    being a subclass in python

    View Slide

  20. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Either a class is a REAL subclass
    class ChildClass(ParentClass):
    pass
    ChildClass knows ParentClass
    ParentClass doesn’t know ChildClass

    View Slide

  21. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Or a VIRTUAL subclass
    ParentClass.register(ChildClass)
    ParentClass knows ChildClass
    ChildClass doesn’t know ParentClass

    View Slide

  22. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Classes that can register other classes are called
    Abstract Base Classes or ABCs.
    ...
    Sequence.register(tuple)
    Sequence.register(str)
    Sequence.register(range)
    ...
    MutableSequence.register(list)
    ...
    https://github.com/python/cpython/blob/master/Lib/_collections_abc.py

    View Slide

  23. Abstract Base Classes – LEonardo GIordani - @LGiordani
    registering is a promise: no check!

    View Slide

  24. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Example
    >>> import collections
    >>> class MyClass:
    ... pass
    ...
    >>>

    View Slide

  25. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Example
    >>> import collections
    >>> class MyClass:
    ... pass
    ...
    >>> issubclass(MyClass, collections.Sequence)
    False
    >>>

    View Slide

  26. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Example
    >>> import collections
    >>> class MyClass:
    ... pass
    ...
    >>> issubclass(MyClass, collections.Sequence)
    False
    >>> collections.Sequence.register(MyClass)

    >>>

    View Slide

  27. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Example
    >>> import collections
    >>> class MyClass:
    ... pass
    ...
    >>> issubclass(MyClass, collections.Sequence)
    False
    >>> collections.Sequence.register(MyClass)

    >>> issubclass(MyClass, collections.Sequence)
    True
    >>>

    View Slide

  28. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Abstract base classes are categories

    View Slide

  29. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Level 3

    View Slide

  30. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Build your own Abstract Base Class
    (straight from the docs)
    from abc import ABCMeta
    class MyABC(metaclass=ABCMeta):
    pass
    MyABC.register(tuple)
    assert issubclass(tuple, MyABC)
    assert isinstance((), MyABC)

    View Slide

  31. Abstract Base Classes – LEonardo GIordani - @LGiordani
    WHY METACLASSES?

    View Slide

  32. Abstract Base Classes – LEonardo GIordani - @LGiordani
    DON'T PANIC
    (The Hitchhiker's Guide to the Galaxy)

    View Slide

  33. Abstract Base Classes – LEonardo GIordani - @LGiordani
    When you build an instance you use a class.
    The class can put things into the instance.
    # Class definition
    class Book():
    def __init__(self):
    self.answer = 42
    # Link instance and class
    b = Book()
    # Use the instance
    assert b.answer == 42

    View Slide

  34. Abstract Base Classes – LEonardo GIordani - @LGiordani
    When you build a class you use a metaclass.
    The metaclass can put things into the class.
    # Metaclass definition
    class AnswerType(type):
    def __init__(self, name, bases, namespace):
    self.answer = 42
    # Link class and metaclass
    class Book(metaclass=AnswerType): pass
    # Use the class
    assert Book.answer == 42

    View Slide

  35. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Let’s compare the two side by side
    # Class definition
    class Book():
    def __init__(self):
    self.answer = 42
    # Link instance and class
    b = Book()
    # Use the instance
    assert b.answer == 42
    # Metaclass definition
    class AnswerType(type):
    def __init__(self, ...):
    self.answer = 42
    # Link class and metaclass
    class Book(metaclass=AnswerType): pass
    # Use the class
    assert Book.answer == 42

    View Slide

  36. Abstract Base Classes – LEonardo GIordani - @LGiordani
    it. is. simple.

    View Slide

  37. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Here the metaclass puts the register()
    method in the new class
    from abc import ABCMeta
    class MyABC(metaclass=ABCMeta):
    pass
    MyABC.register(tuple)
    assert issubclass(tuple, MyABC)
    assert isinstance((), MyABC)

    View Slide

  38. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Metaclasses are inherited
    from abc import ABCMeta
    class MyABC(metaclass=ABCMeta):
    pass
    class OtherABC(MyABC):
    pass
    OtherABC.register(tuple)
    assert issubclass(tuple, OtherABC)
    assert issubclass(tuple, MyABC)

    View Slide

  39. Abstract Base Classes – LEonardo GIordani - @LGiordani
    You can use ABCs to build interfaces
    from abc import ABCMeta, abstractmethod
    class StatusInterface(metaclass=ABCMeta):
    @abstractmethod
    def status(self):
    pass
    si = StatusInterface()
    TypeError: Can't instantiate abstract class StatusInterface with abstract methods status

    View Slide

  40. Abstract Base Classes – LEonardo GIordani - @LGiordani
    You can use ABCs to build interfaces
    from abc import ABCMeta, abstractmethod
    class StatusInterface(metaclass=ABCMeta):
    @abstractmethod
    def status(self):
    pass
    class MyStatusView(StatusInterface):
    pass
    msv = MyStatusView()
    TypeError: Can't instantiate abstract class MyStatusView with abstract methods status

    View Slide

  41. Abstract Base Classes – LEonardo GIordani - @LGiordani
    Questions & ANSWERS

    View Slide

  42. Abstract Base Classes – LEonardo GIordani - @LGiordani
    AMQP - architectures - C - Clojure - compilers
    concurrent programming - C++ decorators - Django - Erlang
    functional programming - generators - Git - metaclasses
    metaprogramming - Notebook - OOP - operating systems
    Python - Python2 - Python3 - RabbitMQ - Scala - TDD
    testing - versioning
    http://thedigitalcatonline.com
    @thedigicat

    View Slide

  43. Abstract Base Classes – LEonardo GIordani - @LGiordani
    THANKS

    View Slide