Interfaces in Python¶
A work-in-progress reference all about interfaces in Python.
Feel free to give me feedback on the project page
- My PyCon talk on interfaces:
- slides <https://docs.google.com/present/...> on the PyCon site <https://us.pycon.org/2012/schedule/presentation/126/>
Abstract API Model Approaches¶
Informally specified protocols, facilitated by duck-typing, have been the mainstay of Python since the beginning. Since 2.6/3.0 abstract base classes have been available as a formal means of specifying interfaces. Other proposals have come and gone.
Python also makes it pretty easy to build-your-own interface system, as evidenced by the variety of solutions out there.
Python is a strongly-typed, dynamically-typed, interpreted language. Let’s take a look at the data model a bit more.
This is the bread and butter of Python’s interfaces.
Abstract Base Classes¶
Abstract base classes have been a part of Python since the Py3k efforts led to PEP 3119 in 2007.
Interfaces in Python¶
- the Great Adaptation Debate of 2005
Python’s Data Model¶
Objects are Python.s abstraction for data. All data in a Python program is represented by objects or by relations between objects.
So, everything is an object in Python, including modules, classes, and literals. Every object is an instance of the base object type or of a subclass thereof:
class X: pass isinstance(object(), object) == True isinstance(object, object) == True isinstance("abc", object) == True isinstance(1, object) == True isinstance(X, object) == True isinstance(X(), object) == True isinstance(type, object) == True
Every object has a type and every type is an instance of the base type:
class MetaY(type): pass class Y(metaclass=MetaY) type(object()) == object type(object) == type isinstance(object, type) == True type("abc") == str isinstance(str, type) == True type(1) == int isinstance(int, type) == True type(X()) == X type(X) == type isinstance(X, type) == True type(Y) == MetaY isinstance(Y, type) == True type(type) == type isinstance(type, type) == True
Be sure to notice the special-cased nature of the base object and base type:
type(type) == type isinstance(type, object) == True type(object) == type isinstance(object, object) == True
Python’s Dynamic Typing¶
Names don’t have type declarations, like they do in statically-typed languages. You could also look at it like all names have the same implicit type declaration: object. Either way, any object can be bound to any valid name (including as a function argument).
Objects are bound to names. Names are not bound to objects. As a consequence, objects do not “know” the names to which they are bound.
“Polymorphism without inheritance”
Duck-typing is polymorphism by capability, as opposed to polymorphism by type.
- “signature-based” polymorphism <http://zephyrfalcon.org/labs/beginners_mistakes.html>
- Requiring a specific interface instead of a specific type. <>
- Determining an object’s type by inspection of its method / attribute signature rather than by explicit relationship to some type object. <>
- Even without formal interface declarations, good practice mostly depends on conformant interfaces rather than subclassing to determine an object’s type. <>
Python has always been about what an object can do, rather than its type. This has changed somewhat with the advent of abstract base classes (see PEP 3119), where isinstance checks lessen the performance hit of LBYL (see below).
Key Concept: LBYL vs. EAFP¶
LBYL: look before you leap EAFP: easier to ask forgiveness than get permission
EAFP is more pythonic.
Duck-typing is all about the attributes an object has and what that object can do. For example:
# LBYL if hasattr(obj, "quack"): obj.quack() #EAFP try: quack = obj.quack except Exception: ... quack() #EAFP - just try it obj.quack()
This is not duck-typing (though perfectly valid):
# LBYL if isinstance(obj, Duck): obj.quack() # LBYL if implements(obj, Duck): obj.quack()
While duck-typing is an integral part of writing Python, the application of it in the language itself is a key part of understanding how Python works under the hood.
Abstract Base Classes in Python¶
http://docs.python.org/dev/library/abc.html http://stackoverflow.com/questions/3570796/why-use-abstract-base-classes-in-python http://www.doughellmann.com/PyMOTW/abc/ http://mail.python.org/pipermail/python-ideas/2011-October/012075.html http://sayspy.blogspot.com/2009/12/how-to-handle-multiple-inheritance-of.html http://www.python.org/dev/peps/pep-3119/#abcs-vs-alternatives http://docs.python.org/whatsnew/2.6.html#pep-3119-abstract-base-classes
Duck-typing is focused on protocols. ABC/Interface is focused on formal interfaces.
ABC/Interface vs. duck-typing – means LBYL vs. EAFP?
- Test for IX w/o using it. Tests for all of it vs.
- Test for IX by using a part of it, when you need it. Only use what you need.