![Mastering Objectoriented Python](https://wfqqreader-1252317822.image.myqcloud.com/cover/948/36704948/b_36704948.jpg)
Metaclass example 1 – ordered attributes
This is the canonical example in section 3.3.3, Customizing Class Creation, of Python Language Reference. This metaclass will record the order in which the attributes and method functions are defined.
The recipe has the following three parts:
- Create a metaclass. The
__prepare__()
and__new__()
functions of that metaclass will change the way a target class is built, replacing a plain-olddict
class with theOrderedDict
class. - Create an abstract superclass that is based on the metaclass. This abstract class simplifies the inheritance for other classes.
- Create subclasses of the abstract superclass that benefit from the metaclass.
The following is the example metaclass that will retain the order of the creation of the attribute:
import collections class Ordered_Attributes(type): @classmethod def __prepare__(metacls, name, bases, **kwds): return collections.OrderedDict() def __new__(cls, name, bases, namespace, **kwds): result = super().__new__(cls, name, bases, namespace) result._order = tuple(n for n in namespace if not n.startswith('__')) return result
This class extends the built-in default metaclass, type
, with a new version of __prepare__()
and __new__()
.
The __prepare__()
method is executed prior to the creation of the class; its job is to create the initial namespace object into which the definitions will be added. This method could work on any other preparation prior to the execution of the class body that is being processed.
The __new__()
static method is executed after the class body elements have been added to the namespace. It is given the class object, the class name, the superclass tuple, and the fully built namespace mapping object. This example is typical: it delegates the real work of __new__()
to the superclass; the superclass of a metaclass is the built-in type
; we use type.__new__()
to create the default class object that can be tweaked.
The __new__()
method in this example adds an attribute, _order
, into the class definition that shows us the original order of the attributes.
We can use this metaclass instead of type
when defining a new abstract superclass, as follows:
class Order_Preserved( metaclass=Ordered_Attributes ): pass
We can then use this new abstract class as the superclass for any new classes that we define, as follows:
class Something( Order_Preserved ): this= 'text' def z( self ): return False b= 'order is preserved' a= 'more text'
When we look at the Something
class, we see the following code snippet:
>>> Something._order >>> ('this', 'z', 'b', 'a')
We can consider exploiting this information to properly serialize the object or provide debugging information that is tied to the original source definitions.