Using Mix-ins with Python
The most straightforward way to apply mix-ins is at design time within the construction of a module. One of the more famous third-party modules for Python, MySQLdb, does exactly this.
Python defines a standard programmatic interface for database access named DB API (http://www.python.org/topics/database/). Andy Dustman's MySQLdb module implements this interface so that Python programmers can make connections and send queries to a MySQL server. It can be found at http://dustman.net/andy/python/MySQLdb/.
MySQLdb provides three major features for the cursor objects it creates. It reports warnings when necessary; it stores result sets on the client side or uses them on the server side as needed, and it returns results as tuples (e.g., immutable lists) or dictionaries.
Rather than combining all of these into one monolithic class, MySQLdb defines mix-in classes for each of them:
class CursorWarningMixIn: class CursorStoreResultMixIn: class CursorUseResultMixIn class CursorTupleRowsMixIn: class CursorDictRowsMixIn(CursorTupleRowsMixIn):
Remember that mix-ins are classes, so they can take advantage of inheritance, as we see with CursorDictRowsMixIn, which inherits CursorTupleRowsMixIn.
None of the mix-ins above can stand on their own: a BaseCursor class provides the required core functionality for any type of cursor. Using these mix-ins in combination with BaseCursor, MySQLdb offers every combination of warnings, storage and result types (eight in all). When creating a database connection, you can pass the cursor class you desire:
conn = MySQLdb.connection (cursorclass=MySQLdb.DictCursor)
Mix-ins don't only help in the creation of MySQLdb itself. They also make it more extensible by allowing you to pick and choose features for your own custom cursor classes.
Note that these class names are suffixed with MixIn to emphasize their nature. Another common convention is to append “-able” or “-ible” to the end of the name as in Configurable or NamedValueAccessible.
Let's use that last one as an example. The NamedValueAccessible mix-in adds the method valueForKey( ) to whatever class with which it is joined. For obj.valueForKey(name), this method will return one of the following:
In other words, valueForKey( ) looks for methods or attributes, either public or private, in order to return a value for the given key. The design of this method reflects the fact that Python objects often provide information through both attributes and methods. See Listing 2 for the implementation.
A useful application of this mix-in is to implement generic code for writing logs (see Listing 3).
By simply adding new keys to the logColumns( ) method, the log can be expanded without having to modify the code that generates it, which is found in logEntry( ). More importantly, you can imagine that logColumns( ) could read its list of fields from a simple configuration file.
The transaction object itself is free to provide the given values via either methods or attributes, due to the flexibility of the valueForKey( ) method. Making mix-ins flexible increases their utility and is an art that can be developed over time.
So far we have seen examples of using mix-ins during the construction of classes. However, Python's dynamic nature also allows us to mix in functionality at runtime. The simplest technique for doing so is to modify the base classes of the given class, as described earlier. A function allows us to keep this operation opaque and enhance it later if need be:
def MixIn(pyClass, mixInClass): pyClass.__bases__ += mixInClass
Let's consider a situation that makes the utility of MixIn( ) obvious. In the construction of internet applications, keeping domain classes separate from interface classes is generally a good idea. Domain classes represent the concepts, data and operations of a specific application. They are independent of operating system, user interface, database, etc. Some writers refer to domain objects as business objects, model objects or problem space objects.
Keeping the domain and interface separate makes sense for various reasons. An individual focus is created for two key areas that are largely independent: What is the subject material of the problem? And, how should that be presented? New interfaces can be constructed without modifying or rewriting the domain classes. In fact, multiple interfaces can be provided.
Domain classes for a story publishing system might include Story, Author and Site. These classes contain essential attributes (such as title, body, name, e-mail, etc.) and various operations (save, load, publish, etc.).
One interface for such a system could be a web site that allows users to create, edit, delete and publish these stories. When developing such a site, it would be useful if our domain classes, such as Story, have the methods renderView( ) and renderForm( ), which write HTML for either displaying the story or editing it with a form.
Using mix-ins, we can develop such functionality outside of the domain classes:
class StoryInterface: def renderView(self): # write the HTML representation of the story pass def renderForm(self): # write the HTML form to edit the story pass
And within the code that backs the web site, mix it in like so:
from MixIn import MixIn from Domain.Story import Story MixIn(Story, StoryInterface)If you decide to create a GUI interface for the publishing system, you don't have to take the HTML machinery with you (or vice versa). The domain classes focus on providing necessary data and operations, ensuring that when developing the GUI, you will have what you need.
One could argue that a new class might be created to bring the two together:
class StoryInterface: ... from Domain.Story import Story class Story(Story, StoryInterface): pass
Or one could argue that StoryInterface might be made a subclass of Story in order to achieve the same benefit. However, consider the case when Story already has other domain subclasses:
class Story: ... class Editorial(Story): ... class Feature(Story): ... class Column(Story): ...Existing subclasses of Story are in no way affected by simply creating a new Story class or subclass. But a dynamic mix-in for Story will also affect Editorial, Feature and Column. That is why many times the static approach does not work in practice, thereby making the dynamic approach not only clever, but necessary.
Also, consider the case where Story objects are created in parts of the code where Story is hard-coded. While poor practice, this is common. In this situation, creating subclasses of Story will have no effect on the code that ignores them.
One warning regarding dynamic mix-ins: they can change the behavior of existing objects (because they change the classes of those objects). This could lead to unpredictable results, as most classes are not designed with that type of change in mind. The safe way to use dynamic mix-ins is to install them when the application first starts, before any objects are created.
Fast/Flexible Linux OS Recovery
On Demand Now
In this live one-hour webinar, learn how to enhance your existing backup strategies for complete disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible full-system recovery solution for UNIX and Linux systems.
Join Linux Journal's Shawn Powers and David Huffman, President/CEO, Storix, Inc.
Free to Linux Journal readers.Register Now!
- Devuan Beta Release
- May 2016 Issue of Linux Journal
- EnterpriseDB's EDB Postgres Advanced Server and EDB Postgres Enterprise Manager
- The US Government and Open-Source Software
- The Humble Hacker?
- BitTorrent Inc.'s Sync
- The Death of RoboVM
- Open-Source Project Secretly Funded by CIA
- New Container Image Standard Promises More Portable Apps
- AdaCore's SPARK Pro
In modern computer systems, privacy and security are mandatory. However, connections from the outside over public networks automatically imply risks. One easily available solution to avoid eavesdroppers’ attempts is SSH. But, its wide adoption during the past 21 years has made it a target for attackers, so hardening your system properly is a must.
Additionally, in highly regulated markets, you must comply with specific operational requirements, proving that you conform to standards and even that you have included new mandatory authentication methods, such as two-factor authentication. In this ebook, I discuss SSH and how to configure and manage it to guarantee that your network is safe, your data is secure and that you comply with relevant regulations.Get the Guide