Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Abstract Base Classes – LEonardo GIordani - @LGiordani Level 1

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Abstract Base Classes – LEonardo GIordani - @LGiordani Level 2

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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 >>>

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Abstract Base Classes – LEonardo GIordani - @LGiordani Level 3

Slide 30

Slide 30 text

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)

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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)

Slide 38

Slide 38 text

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)

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Abstract Base Classes – LEonardo GIordani - @LGiordani THANKS