HomePython Page 4 - Metaclasses: Blueprints of Blueprints
Using Metaclasses - Python
We all know that objects are created from classes. But can a class be created from a class? Yes it can; this is called a metaclass. They give us a great deal of power when it comes to changing the behavior of a class. Python 2.2 supports metaclasses. Peyton McCullough explains.
You're probably wondering when and where to use metaclasses. While there is no rule that tells us exactly that, we can look over a few situations where metaclasses can be used.
We'll start with a widely-used example, and then we'll build some features onto it to form more examples. Take a look at class E:
>>> class E: pass
If we try to print the class out, we get a string representation of E:
>>> print E
What if we want to change the output to something more informative, though? This requires changing the behavior of the class. The words “changing the behavior” should have sounded an alarm in your mind. Metaclasses are perfect for changing the behavior of a class.
If we were performing our work on an object, we would simply define a __str__ method in the parent class. Since we're working with a class, though, we need to define the method in the metaclass. The method needs to return a string with the description we want:
>>> class MetaF ( type ): def __str__ ( cls ): return "A class made from metaclass MetaF"
We have now achieved the desired behavior:
>>> class F ( object ): __metaclass__ = MetaF
>>> print F A class made from metaclass MetaF >>> str ( F ) 'A class made from metaclass MetaF'
We can also go above and beyond, though. Instead of having a generic message to describe what may be an entire set of classes, we can give each class the capability to define a custom message. The message can be stored in a predefined variable that each class can change. This variable can be returned in our metaclass's __str__ method. Take a look at metaclass MetaG:
>>> class MetaG ( type ): __nameString__ = 'A class made from metaclass MetaG' def __str__ ( cls ): return cls.__nameString__
Each class made from MetaG will contain the variable __nameString__ and can change it. When we request a string representation of each class, its __nameString__ variable will then be returned:
>>> class G ( object ): __metaclass__ = MetaG
>>> print G
A class made from metaclass MetaG
>>> class G ( object ): __metaclass__ = MetaG __nameString__ = 'A class named G'