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

Abstract Base Classes

Embed Size (px)

Citation preview

Page 1: Abstract Base Classes

Abstract Base ClassesA smart use of metaclasses in Python

LEonardo GIordani @LGiordani

http://thedigitalcatonline.com

Page 2: Abstract Base Classes

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

Page 3: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Overview

EAFP and complex tests – Polymorphism – Collections

Registering – Abstract Base Classes – Categories

Build your ABCs – MRO with metaclasses – Mixins

Level 1

Level 2

Level 3

Page 4: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Level 1

Page 5: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

OOP: behaviour over structure

Page 6: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Python EAFPTest the behaviour, not the structure

try: someobj[1]except TypeError: # object is not subscriptable ...

Page 7: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Some checks are complex.How to check if something behaves like a list?

try: someobj.append someobj.extend someobj.index ...except AttributeError: ...

This is checking the structure: wrong.

Page 8: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Temptation

if isinstance(someobj, list): ...

This is checking the type: wrong.

Page 9: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Python is strongly based on delegation.Change isinstance() and issubclass():

issubclass(myclass, someclass)

someclass.__subclasscheck__(myclass)

becomes

Page 10: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Collectionsclasses that represent interesting behaviours

>>> import collections>>>>>> isinstance(“a string”, collections.Sequence)True>>>>>> isinstance(“a string”, collections.Mapping)False>>>

Page 11: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Level 2

Page 12: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

being a subclass in python

Page 13: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Either a class is a REAL subclass

class ChildClass(ParentClass): pass

Page 14: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Or a VIRTUAL subclass

ParentClass.register(ChildClass)

Page 15: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Classes that can register() other classes are calledAbstract Base Classes or ABCs.

...Sequence.register(tuple)Sequence.register(str)Sequence.register(range)...MutableSequence.register(list)...

from python3.4/_collections_abc.py

Page 16: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

registering is a promise: no check!

Page 17: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Example

>>> import collections>>> class MyClass:... pass... >>>

Page 18: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Example

>>> import collections>>> class MyClass:... pass... >>> issubclass(MyClass, collections.Sequence)False>>>

Page 19: Abstract Base Classes

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

Page 20: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Abstract base classes are categories

Page 21: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Level 3

Page 22: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

HOW TO DEFINE YOUR ABC

Page 23: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Build your own Abstract Base Class(stright from the docs)

from abc import ABCMeta

class MyABC(metaclass=ABCMeta): pass

MyABC.register(tuple)

assert issubclass(tuple, MyABC)assert isinstance((), MyABC)

Page 24: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

WHY METACLASSES?

Page 25: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

DON'T PANIC(The Hitchhiker's Guide to the Galaxy)

Page 26: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

When you build an instance you use a class.The class can put things into the instance.

# Class definitionclass Child():

def __init__(self):self.answer = 42

# Link instance and classc = Child()

# Use the instanceassert c.answer == 42

Page 27: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

When you build a class you use a metaclass.The metaclass can put things into the class.

# Metaclass definitionclass NewType(type):

def __init__(self, name, bases, namespace):self.answer = 42

# Link class and metaclassclass Child(metaclass=NewType): pass

# Use the classassert Child.answer == 42

Page 28: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

it. is. simple.

Page 29: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

What happens to the MRO?

class Parent: @classmethod def whoami(cls): return "Parent"

class NewType(type): def whoami(self): return "NewType"

class Child(Parent, metaclass=NewType): pass

assert Child.whoami() == “Parent”

Page 30: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

METACLASSES ARE MIXINS FOR CLASSES

Page 31: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Check the documentation for @abstractmethod and @abstractproperty

class Hashable(metaclass=ABCMeta):

[...]

@abstractmethod def __hash__(self): return 0

[...]

Page 32: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Questions & ANSWERS

Page 33: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

Interested in AMQP, C, Clojure, concurrent programming, C++, decorators, Django, Erlang, functional programming, generators, Git, metaclasses, metaprogramming, Notebook, OOP, operating systems,

Python, Qt, RabbitMQ, Scala, TDD, versioning?

http://thedigitalcatonline.com@thedigicat

Page 34: Abstract Base Classes

Abstract Base Classes – LEonardo GIordani - @LGiordani

THANKS