Using Mix-ins with Python
Mix-in programming is a style of software development where units of functionality are created in a class and then mixed in with other classes. This might sound like simple inheritance at first, but a mix-in differs from a traditional class in one or more of the following ways. Often a mix-in is not the “primary” superclass of any given class, does not care what class it is used with, is used with many classes scattered throughout the class hierarchy and is introduced dynamically at runtime.
There are several reasons to use mix-ins: they extend existing classes in new areas without having to edit, maintain or merge with their source code; they keep project components (such as domain frameworks and interface frameworks) separate; they ease the creation of new classes by providing a grab bag of functionalities that can be combined as needed; and they overcome a limitation of subclassing, whereby a new subclass has no effect if objects of the original class are still being created in other parts of the software.
So while mix-ins are not a distinct technical feature of Python, the benefits of this technique are worth studying.
Python provides an ideal language for mix-in development because it supports multiple inheritance, supports full-dynamic binding and allows dynamic changes to classes. Before we dive into Python, let me admit that mix-ins are old hat. The first time I saw mix-in programming by that name was when reviewing the now-defunct Taligent Project, known for its Pink operating system and CommonPoint application framework. However, since C++ does not support language feature #2, full-dynamic binding, or language feature #3, dynamic changes at runtime, I'm not surprised that the approach didn't bring to fruition all its inventors had hoped for.
I have also seen another instance of mix-in programming under a different name. Objective-C has a nifty language feature called categories that allows you to add and replace methods of existing classes, even without access to their source code.
This is great for repairing existing system classes and extending their capabilities. Also, combined with an ability to load libraries dynamically, categories are quite effective in improving the structure of applications and reducing code.
The grapevine informs me that Symbolics' object-oriented Flavors system is most likely the earliest appearance of bona fide mix-ins. The designers were inspired by Steve's Ice Cream Parlor in Cambridge, Massachusetts where customers started with a basic flavor of ice cream (vanilla, chocolate, etc.) and added any combination of mix-ins (nuts, fudge, chocolate chips, etc.). In the Symbolics system, large, standalone classes were known as flavors while smaller helper classes designed for enhancing other classes were known as mix-ins. A reference can be found on the Web at www.kirkrader.com/examples/cpp/mixin.htm.
Having paid our respects to the dead (Taligent), nearly dead (Objective-C) and legendary (Symbolics), let's start digging into the features that make Python a great language for mix-in programming. For one, Python supports multiple inheritance. That is, in Python, a class can inherit more than one class:
class Server(Object, Configurable): pass
also, Python supports full-dynamic binding. When passing a message to an object such as:
obj.load(filename)Python will determine, entirely at runtime, what method to invoke, based on the name of the message and the class inheritance of obj. This behavior works as expected and is easy to remember. It continues to work even if the class inheritance or method definitions are altered at runtime.
One thing to keep in mind is the order of searching with regard to multiple inheritance. The search order goes from left to right through the base classes, and for any given base class, goes deep into its ancestor classes.
When you create mix-ins, keep in mind the potential for method names to clash. By creating distinct mix-ins with well-named methods you can generally avoid any surprises. Lastly, Python supports dynamic changes to the class hierarchy.
Most Python “things”, whether they are lists, dictionaries, classes or instances, have a set of accessible attributes. Python classes have an attribute named __bases__, which is a tuple of their base classes. Consistent with Python design, you can play with it at runtime. In the following session with the Python interactive interpreter seen in Listing 1, we create two classes and then later change the inheritance. Our person in Listing 1 isn't very friendly so let's change it. In fact, let's change all people so that we'll never have this problem again:
<<< Person.__bases__ += (Friendly,) <<< p.hello() Hello
The first statement above changes the base classes of Person. By using += (as opposed to =) we avoid accidentally removing existing base classes, especially if a future version of the code makes Person inherit from another class. Also, the funny looking expression, (Friendly,), specifies a tuple that would normally simply be enclosed in parenthesis. However, while Python readily recognizes <If“Courier”>(x,y)<I$f$> as a tuple of two elements, it recognizes <If“Courier”>(x)<I$f$> as a parenthesized expression. Appending the comma forces tuple recognition.
|Speed Up Your Web Site with Varnish||Jun 19, 2013|
|Non-Linux FOSS: libnotify, OS X Style||Jun 18, 2013|
|Containers—Not Virtual Machines—Are the Future Cloud||Jun 17, 2013|
|Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer||Jun 12, 2013|
|Weechat, Irssi's Little Brother||Jun 11, 2013|
|One Tail Just Isn't Enough||Jun 07, 2013|
- Speed Up Your Web Site with Varnish
- Containers—Not Virtual Machines—Are the Future Cloud
- RSS Feeds
- Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
- Non-Linux FOSS: libnotify, OS X Style
- Linux Systems Administrator
- Weechat, Irssi's Little Brother
- Senior Perl Developer
- Technical Support Rep
- UX Designer
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?