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
  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
  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
  4. Abstract Base Classes – LEonardo GIordani - @LGiordani Level 1

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

    over structure
  6. Abstract Base Classes – LEonardo GIordani - @LGiordani Python EAFP

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

    behaviour class ListView(View): def status(self): ... class ItemView(View): def status(self): ...
  8. Abstract Base Classes – LEonardo GIordani - @LGiordani How to

    check how an object behaves? try: someobj.status except AttributeError: ...
  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
  10. Abstract Base Classes – LEonardo GIordani - @LGiordani Temptation if

    isinstance(someobj, list): ... This is checking the type: wrong
  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
  12. Abstract Base Classes – LEonardo GIordani - @LGiordani Perfect solution

    if behaveslike(someobj, ListBehaviour): ...
  13. Abstract Base Classes – LEonardo GIordani - @LGiordani Python is

    based on delegation
  14. Abstract Base Classes – LEonardo GIordani - @LGiordani Original version

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

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

    now possible if isinstance(someobj, ListBehaviour): ... We just need to implement “behaviour” classes
  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
  18. Abstract Base Classes – LEonardo GIordani - @LGiordani Level 2

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

    subclass in python
  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
  21. Abstract Base Classes – LEonardo GIordani - @LGiordani Or a

    VIRTUAL subclass ParentClass.register(ChildClass) ParentClass knows ChildClass ChildClass doesn’t know ParentClass
  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
  23. Abstract Base Classes – LEonardo GIordani - @LGiordani registering is

    a promise: no check!
  24. Abstract Base Classes – LEonardo GIordani - @LGiordani Example >>>

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

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

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

    import collections >>> class MyClass: ... pass ... >>> issubclass(MyClass, collections.Sequence) False >>> collections.Sequence.register(MyClass) <class '__main__.MyClass'> >>> issubclass(MyClass, collections.Sequence) True >>>
  28. Abstract Base Classes – LEonardo GIordani - @LGiordani Abstract base

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

  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)
  31. Abstract Base Classes – LEonardo GIordani - @LGiordani WHY METACLASSES?

  32. Abstract Base Classes – LEonardo GIordani - @LGiordani DON'T PANIC

    (The Hitchhiker's Guide to the Galaxy)
  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
  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
  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
  36. Abstract Base Classes – LEonardo GIordani - @LGiordani it. is.

    simple.
  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)
  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)
  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
  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
  41. Abstract Base Classes – LEonardo GIordani - @LGiordani Questions &

    ANSWERS
  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
  43. Abstract Base Classes – LEonardo GIordani - @LGiordani THANKS