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/>
understanding_software/interfaces
Abstract API Model Approaches¶
Python
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.
Data Types¶
Python
Python is a strongly-typed, dynamically-typed, interpreted language. Let’s take a look at the data model a bit more.
Class-based Approaches¶
Abstract Base Classes¶
Python
Abstract base classes have been a part of Python since the Py3k efforts led to PEP 3119 in 2007.
Adaptation¶
Traits¶
Interfaces in Python¶
History¶
- the Great Adaptation Debate of 2005
Python’s Data Model¶
http://docs.python.org/dev/reference/datamodel.html:
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.
Duck-typing¶
“Polymorphism without inheritance”
http://en.wikipedia.org/wiki/Duck_typing
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.
Examples¶
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()
Python’s Protocols¶
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.
http://stackoverflow.com/questions/5589532/try-catch-or-validation-for-speed/5591737#5591737
collections.abc¶
Writing Your Own ABC¶
Controversies¶
Interfaces throughout Python’s History
In-the-wild Examples of Abstract Base Classes
Third-Party Python Interface Libraries
Interfaces in Different Languages
/understanding_software/concurrency