Inspired by a great question (and bunch of great answers) from here.
Does the statement \"Code against an interface, not an object\" have any significance in Python?
"Code against an interface, not an object" doesn't make literal sense in Python because the language doesn't have an interface feature. The rough Python equivalent is "use duck typing." If you want to see if an object is a duck, in other words, you should check to see whether it has a quack()
method, or better yet try to quack()
and provide appropriate error handling, not test to see if it is an instance of Duck
.
Common duck types in Python are files (well, really, file-like objects), mappings (dict
-like objects), callables (function-like objects), sequences (list
-like objects), and iterables (things you can iterate over, which can be containers or generators).
As an example, Python features that want a file will generally be happy to accept an object that implements the methods of file
it needs; it needn't be derived from the file
class. To use an object as standard out, for example, the main thing it is going to need is a write()
method (and maybe flush()
and close()
, which needn't actually do anything). Similarly, a callable is any object that has a __call__()
method; it needn't be derived from the function type (in fact, you can't derive from the function type).
You should take a similar approach. Check for the methods and attributes you need for what you're going to do with an object. Better yet, document what you expect and assume that whoever is calling your code is not a total doofus. (If they give you an object you can't use, they will certainly figure that out quickly enough from the errors they get.) Test for specific types only when necessary. It is necessary at times, which is why Python gives you type()
, isinstance()
, and issubclass()
, but be careful with them.
Python's duck typing is equivalent to "code against an interface, not an object" in the sense that you're advised not to make your code too reliant on an object's type, but rather to see whether it has the interface you need. The difference is that in Python, "interface" just means an informal bundle of attributes and methods of an object that provide a certain behavior, rather than a language construct specifically named interface
.
You can formalize Python "interfaces" to some extent using the abc
module, which allows you to declare that a given class is a subclass of a given "abstract base class" (interface) using any criteria you desire, such as "it has attributes color
, tail_length
, and quack
, and quack
is callable." But this is still much less strict than static languages having an interface feature.