]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.2/Demo/metaclasses/index.html
AppPkg/Applications/Python: Add Python 2.7.2 sources since the release of Python...
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Demo / metaclasses / index.html
CommitLineData
4710c53d 1<HTML>\r
2\r
3<HEAD>\r
4<TITLE>Metaclasses in Python 1.5</TITLE>\r
5</HEAD>\r
6\r
7<BODY BGCOLOR="FFFFFF">\r
8\r
9<H1>Metaclasses in Python 1.5</H1>\r
10<H2>(A.k.a. The Killer Joke :-)</H2>\r
11\r
12<HR>\r
13\r
14(<i>Postscript:</i> reading this essay is probably not the best way to\r
15understand the metaclass hook described here. See a <A\r
16HREF="meta-vladimir.txt">message posted by Vladimir Marangozov</A>\r
17which may give a gentler introduction to the matter. You may also\r
18want to search Deja News for messages with "metaclass" in the subject\r
19posted to comp.lang.python in July and August 1998.)\r
20\r
21<HR>\r
22\r
23<P>In previous Python releases (and still in 1.5), there is something\r
24called the ``Don Beaudry hook'', after its inventor and champion.\r
25This allows C extensions to provide alternate class behavior, thereby\r
26allowing the Python class syntax to be used to define other class-like\r
27entities. Don Beaudry has used this in his infamous <A\r
28HREF="http://maigret.cog.brown.edu/pyutil/">MESS</A> package; Jim\r
29Fulton has used it in his <A\r
30HREF="http://www.digicool.com/releases/ExtensionClass/">Extension\r
31Classes</A> package. (It has also been referred to as the ``Don\r
32Beaudry <i>hack</i>,'' but that's a misnomer. There's nothing hackish\r
33about it -- in fact, it is rather elegant and deep, even though\r
34there's something dark to it.)\r
35\r
36<P>(On first reading, you may want to skip directly to the examples in\r
37the section "Writing Metaclasses in Python" below, unless you want\r
38your head to explode.)\r
39\r
40<P>\r
41\r
42<HR>\r
43\r
44<P>Documentation of the Don Beaudry hook has purposefully been kept\r
45minimal, since it is a feature of incredible power, and is easily\r
46abused. Basically, it checks whether the <b>type of the base\r
47class</b> is callable, and if so, it is called to create the new\r
48class.\r
49\r
50<P>Note the two indirection levels. Take a simple example:\r
51\r
52<PRE>\r
53class B:\r
54 pass\r
55\r
56class C(B):\r
57 pass\r
58</PRE>\r
59\r
60Take a look at the second class definition, and try to fathom ``the\r
61type of the base class is callable.''\r
62\r
63<P>(Types are not classes, by the way. See questions 4.2, 4.19 and in\r
64particular 6.22 in the <A\r
65HREF="http://www.python.org/cgi-bin/faqw.py" >Python FAQ</A>\r
66for more on this topic.)\r
67\r
68<P>\r
69\r
70<UL>\r
71\r
72<LI>The <b>base class</b> is B; this one's easy.<P>\r
73\r
74<LI>Since B is a class, its type is ``class''; so the <b>type of the\r
75base class</b> is the type ``class''. This is also known as\r
76types.ClassType, assuming the standard module <code>types</code> has\r
77been imported.<P>\r
78\r
79<LI>Now is the type ``class'' <b>callable</b>? No, because types (in\r
80core Python) are never callable. Classes are callable (calling a\r
81class creates a new instance) but types aren't.<P>\r
82\r
83</UL>\r
84\r
85<P>So our conclusion is that in our example, the type of the base\r
86class (of C) is not callable. So the Don Beaudry hook does not apply,\r
87and the default class creation mechanism is used (which is also used\r
88when there is no base class). In fact, the Don Beaudry hook never\r
89applies when using only core Python, since the type of a core object\r
90is never callable.\r
91\r
92<P>So what do Don and Jim do in order to use Don's hook? Write an\r
93extension that defines at least two new Python object types. The\r
94first would be the type for ``class-like'' objects usable as a base\r
95class, to trigger Don's hook. This type must be made callable.\r
96That's why we need a second type. Whether an object is callable\r
97depends on its type. So whether a type object is callable depends on\r
98<i>its</i> type, which is a <i>meta-type</i>. (In core Python there\r
99is only one meta-type, the type ``type'' (types.TypeType), which is\r
100the type of all type objects, even itself.) A new meta-type must\r
101be defined that makes the type of the class-like objects callable.\r
102(Normally, a third type would also be needed, the new ``instance''\r
103type, but this is not an absolute requirement -- the new class type\r
104could return an object of some existing type when invoked to create an\r
105instance.)\r
106\r
107<P>Still confused? Here's a simple device due to Don himself to\r
108explain metaclasses. Take a simple class definition; assume B is a\r
109special class that triggers Don's hook:\r
110\r
111<PRE>\r
112class C(B):\r
113 a = 1\r
114 b = 2\r
115</PRE>\r
116\r
117This can be though of as equivalent to:\r
118\r
119<PRE>\r
120C = type(B)('C', (B,), {'a': 1, 'b': 2})\r
121</PRE>\r
122\r
123If that's too dense for you, here's the same thing written out using\r
124temporary variables:\r
125\r
126<PRE>\r
127creator = type(B) # The type of the base class\r
128name = 'C' # The name of the new class\r
129bases = (B,) # A tuple containing the base class(es)\r
130namespace = {'a': 1, 'b': 2} # The namespace of the class statement\r
131C = creator(name, bases, namespace)\r
132</PRE>\r
133\r
134This is analogous to what happens without the Don Beaudry hook, except\r
135that in that case the creator function is set to the default class\r
136creator.\r
137\r
138<P>In either case, the creator is called with three arguments. The\r
139first one, <i>name</i>, is the name of the new class (as given at the\r
140top of the class statement). The <i>bases</i> argument is a tuple of\r
141base classes (a singleton tuple if there's only one base class, like\r
142the example). Finally, <i>namespace</i> is a dictionary containing\r
143the local variables collected during execution of the class statement.\r
144\r
145<P>Note that the contents of the namespace dictionary is simply\r
146whatever names were defined in the class statement. A little-known\r
147fact is that when Python executes a class statement, it enters a new\r
148local namespace, and all assignments and function definitions take\r
149place in this namespace. Thus, after executing the following class\r
150statement:\r
151\r
152<PRE>\r
153class C:\r
154 a = 1\r
155 def f(s): pass\r
156</PRE>\r
157\r
158the class namespace's contents would be {'a': 1, 'f': &lt;function f\r
159...&gt;}.\r
160\r
161<P>But enough already about writing Python metaclasses in C; read the\r
162documentation of <A\r
163HREF="http://maigret.cog.brown.edu/pyutil/">MESS</A> or <A\r
164HREF="http://www.digicool.com/papers/ExtensionClass.html" >Extension\r
165Classes</A> for more information.\r
166\r
167<P>\r
168\r
169<HR>\r
170\r
171<H2>Writing Metaclasses in Python</H2>\r
172\r
173<P>In Python 1.5, the requirement to write a C extension in order to\r
174write metaclasses has been dropped (though you can still do\r
175it, of course). In addition to the check ``is the type of the base\r
176class callable,'' there's a check ``does the base class have a\r
177__class__ attribute.'' If so, it is assumed that the __class__\r
178attribute refers to a class.\r
179\r
180<P>Let's repeat our simple example from above:\r
181\r
182<PRE>\r
183class C(B):\r
184 a = 1\r
185 b = 2\r
186</PRE>\r
187\r
188Assuming B has a __class__ attribute, this translates into:\r
189\r
190<PRE>\r
191C = B.__class__('C', (B,), {'a': 1, 'b': 2})\r
192</PRE>\r
193\r
194This is exactly the same as before except that instead of type(B),\r
195B.__class__ is invoked. If you have read <A HREF=\r
196"http://www.python.org/cgi-bin/faqw.py?req=show&file=faq06.022.htp"\r
197>FAQ question 6.22</A> you will understand that while there is a big\r
198technical difference between type(B) and B.__class__, they play the\r
199same role at different abstraction levels. And perhaps at some point\r
200in the future they will really be the same thing (at which point you\r
201would be able to derive subclasses from built-in types).\r
202\r
203<P>At this point it may be worth mentioning that C.__class__ is the\r
204same object as B.__class__, i.e., C's metaclass is the same as B's\r
205metaclass. In other words, subclassing an existing class creates a\r
206new (meta)inststance of the base class's metaclass.\r
207\r
208<P>Going back to the example, the class B.__class__ is instantiated,\r
209passing its constructor the same three arguments that are passed to\r
210the default class constructor or to an extension's metaclass:\r
211<i>name</i>, <i>bases</i>, and <i>namespace</i>.\r
212\r
213<P>It is easy to be confused by what exactly happens when using a\r
214metaclass, because we lose the absolute distinction between classes\r
215and instances: a class is an instance of a metaclass (a\r
216``metainstance''), but technically (i.e. in the eyes of the python\r
217runtime system), the metaclass is just a class, and the metainstance\r
218is just an instance. At the end of the class statement, the metaclass\r
219whose metainstance is used as a base class is instantiated, yielding a\r
220second metainstance (of the same metaclass). This metainstance is\r
221then used as a (normal, non-meta) class; instantiation of the class\r
222means calling the metainstance, and this will return a real instance.\r
223And what class is that an instance of? Conceptually, it is of course\r
224an instance of our metainstance; but in most cases the Python runtime\r
225system will see it as an instance of a a helper class used by the\r
226metaclass to implement its (non-meta) instances...\r
227\r
228<P>Hopefully an example will make things clearer. Let's presume we\r
229have a metaclass MetaClass1. It's helper class (for non-meta\r
230instances) is callled HelperClass1. We now (manually) instantiate\r
231MetaClass1 once to get an empty special base class:\r
232\r
233<PRE>\r
234BaseClass1 = MetaClass1("BaseClass1", (), {})\r
235</PRE>\r
236\r
237We can now use BaseClass1 as a base class in a class statement:\r
238\r
239<PRE>\r
240class MySpecialClass(BaseClass1):\r
241 i = 1\r
242 def f(s): pass\r
243</PRE>\r
244\r
245At this point, MySpecialClass is defined; it is a metainstance of\r
246MetaClass1 just like BaseClass1, and in fact the expression\r
247``BaseClass1.__class__ == MySpecialClass.__class__ == MetaClass1''\r
248yields true.\r
249\r
250<P>We are now ready to create instances of MySpecialClass. Let's\r
251assume that no constructor arguments are required:\r
252\r
253<PRE>\r
254x = MySpecialClass()\r
255y = MySpecialClass()\r
256print x.__class__, y.__class__\r
257</PRE>\r
258\r
259The print statement shows that x and y are instances of HelperClass1.\r
260How did this happen? MySpecialClass is an instance of MetaClass1\r
261(``meta'' is irrelevant here); when an instance is called, its\r
262__call__ method is invoked, and presumably the __call__ method defined\r
263by MetaClass1 returns an instance of HelperClass1.\r
264\r
265<P>Now let's see how we could use metaclasses -- what can we do\r
266with metaclasses that we can't easily do without them? Here's one\r
267idea: a metaclass could automatically insert trace calls for all\r
268method calls. Let's first develop a simplified example, without\r
269support for inheritance or other ``advanced'' Python features (we'll\r
270add those later).\r
271\r
272<PRE>\r
273import types\r
274\r
275class Tracing:\r
276 def __init__(self, name, bases, namespace):\r
277 """Create a new class."""\r
278 self.__name__ = name\r
279 self.__bases__ = bases\r
280 self.__namespace__ = namespace\r
281 def __call__(self):\r
282 """Create a new instance."""\r
283 return Instance(self)\r
284\r
285class Instance:\r
286 def __init__(self, klass):\r
287 self.__klass__ = klass\r
288 def __getattr__(self, name):\r
289 try:\r
290 value = self.__klass__.__namespace__[name]\r
291 except KeyError:\r
292 raise AttributeError, name\r
293 if type(value) is not types.FunctionType:\r
294 return value\r
295 return BoundMethod(value, self)\r
296\r
297class BoundMethod:\r
298 def __init__(self, function, instance):\r
299 self.function = function\r
300 self.instance = instance\r
301 def __call__(self, *args):\r
302 print "calling", self.function, "for", self.instance, "with", args\r
303 return apply(self.function, (self.instance,) + args)\r
304\r
305Trace = Tracing('Trace', (), {})\r
306\r
307class MyTracedClass(Trace):\r
308 def method1(self, a):\r
309 self.a = a\r
310 def method2(self):\r
311 return self.a\r
312\r
313aninstance = MyTracedClass()\r
314\r
315aninstance.method1(10)\r
316\r
317print "the answer is %d" % aninstance.method2()\r
318</PRE>\r
319\r
320Confused already? The intention is to read this from top down. The\r
321Tracing class is the metaclass we're defining. Its structure is\r
322really simple.\r
323\r
324<P>\r
325\r
326<UL>\r
327\r
328<LI>The __init__ method is invoked when a new Tracing instance is\r
329created, e.g. the definition of class MyTracedClass later in the\r
330example. It simply saves the class name, base classes and namespace\r
331as instance variables.<P>\r
332\r
333<LI>The __call__ method is invoked when a Tracing instance is called,\r
334e.g. the creation of aninstance later in the example. It returns an\r
335instance of the class Instance, which is defined next.<P>\r
336\r
337</UL>\r
338\r
339<P>The class Instance is the class used for all instances of classes\r
340built using the Tracing metaclass, e.g. aninstance. It has two\r
341methods:\r
342\r
343<P>\r
344\r
345<UL>\r
346\r
347<LI>The __init__ method is invoked from the Tracing.__call__ method\r
348above to initialize a new instance. It saves the class reference as\r
349an instance variable. It uses a funny name because the user's\r
350instance variables (e.g. self.a later in the example) live in the same\r
351namespace.<P>\r
352\r
353<LI>The __getattr__ method is invoked whenever the user code\r
354references an attribute of the instance that is not an instance\r
355variable (nor a class variable; but except for __init__ and\r
356__getattr__ there are no class variables). It will be called, for\r
357example, when aninstance.method1 is referenced in the example, with\r
358self set to aninstance and name set to the string "method1".<P>\r
359\r
360</UL>\r
361\r
362<P>The __getattr__ method looks the name up in the __namespace__\r
363dictionary. If it isn't found, it raises an AttributeError exception.\r
364(In a more realistic example, it would first have to look through the\r
365base classes as well.) If it is found, there are two possibilities:\r
366it's either a function or it isn't. If it's not a function, it is\r
367assumed to be a class variable, and its value is returned. If it's a\r
368function, we have to ``wrap'' it in instance of yet another helper\r
369class, BoundMethod.\r
370\r
371<P>The BoundMethod class is needed to implement a familiar feature:\r
372when a method is defined, it has an initial argument, self, which is\r
373automatically bound to the relevant instance when it is called. For\r
374example, aninstance.method1(10) is equivalent to method1(aninstance,\r
37510). In the example if this call, first a temporary BoundMethod\r
376instance is created with the following constructor call: temp =\r
377BoundMethod(method1, aninstance); then this instance is called as\r
378temp(10). After the call, the temporary instance is discarded.\r
379\r
380<P>\r
381\r
382<UL>\r
383\r
384<LI>The __init__ method is invoked for the constructor call\r
385BoundMethod(method1, aninstance). It simply saves away its\r
386arguments.<P>\r
387\r
388<LI>The __call__ method is invoked when the bound method instance is\r
389called, as in temp(10). It needs to call method1(aninstance, 10).\r
390However, even though self.function is now method1 and self.instance is\r
391aninstance, it can't call self.function(self.instance, args) directly,\r
392because it should work regardless of the number of arguments passed.\r
393(For simplicity, support for keyword arguments has been omitted.)<P>\r
394\r
395</UL>\r
396\r
397<P>In order to be able to support arbitrary argument lists, the\r
398__call__ method first constructs a new argument tuple. Conveniently,\r
399because of the notation *args in __call__'s own argument list, the\r
400arguments to __call__ (except for self) are placed in the tuple args.\r
401To construct the desired argument list, we concatenate a singleton\r
402tuple containing the instance with the args tuple: (self.instance,) +\r
403args. (Note the trailing comma used to construct the singleton\r
404tuple.) In our example, the resulting argument tuple is (aninstance,\r
40510).\r
406\r
407<P>The intrinsic function apply() takes a function and an argument\r
408tuple and calls the function for it. In our example, we are calling\r
409apply(method1, (aninstance, 10)) which is equivalent to calling\r
410method(aninstance, 10).\r
411\r
412<P>From here on, things should come together quite easily. The output\r
413of the example code is something like this:\r
414\r
415<PRE>\r
416calling &lt;function method1 at ae8d8&gt; for &lt;Instance instance at 95ab0&gt; with (10,)\r
417calling &lt;function method2 at ae900&gt; for &lt;Instance instance at 95ab0&gt; with ()\r
418the answer is 10\r
419</PRE>\r
420\r
421<P>That was about the shortest meaningful example that I could come up\r
422with. A real tracing metaclass (for example, <A\r
423HREF="#Trace">Trace.py</A> discussed below) needs to be more\r
424complicated in two dimensions.\r
425\r
426<P>First, it needs to support more advanced Python features such as\r
427class variables, inheritance, __init__ methods, and keyword arguments.\r
428\r
429<P>Second, it needs to provide a more flexible way to handle the\r
430actual tracing information; perhaps it should be possible to write\r
431your own tracing function that gets called, perhaps it should be\r
432possible to enable and disable tracing on a per-class or per-instance\r
433basis, and perhaps a filter so that only interesting calls are traced;\r
434it should also be able to trace the return value of the call (or the\r
435exception it raised if an error occurs). Even the Trace.py example\r
436doesn't support all these features yet.\r
437\r
438<P>\r
439\r
440<HR>\r
441\r
442<H1>Real-life Examples</H1>\r
443\r
444<P>Have a look at some very preliminary examples that I coded up to\r
445teach myself how to write metaclasses:\r
446\r
447<DL>\r
448\r
449<DT><A HREF="Enum.py">Enum.py</A>\r
450\r
451<DD>This (ab)uses the class syntax as an elegant way to define\r
452enumerated types. The resulting classes are never instantiated --\r
453rather, their class attributes are the enumerated values. For\r
454example:\r
455\r
456<PRE>\r
457class Color(Enum):\r
458 red = 1\r
459 green = 2\r
460 blue = 3\r
461print Color.red\r
462</PRE>\r
463\r
464will print the string ``Color.red'', while ``Color.red==1'' is true,\r
465and ``Color.red + 1'' raise a TypeError exception.\r
466\r
467<P>\r
468\r
469<DT><A NAME=Trace></A><A HREF="Trace.py">Trace.py</A>\r
470\r
471<DD>The resulting classes work much like standard\r
472classes, but by setting a special class or instance attribute\r
473__trace_output__ to point to a file, all calls to the class's methods\r
474are traced. It was a bit of a struggle to get this right. This\r
475should probably redone using the generic metaclass below.\r
476\r
477<P>\r
478\r
479<DT><A HREF="Meta.py">Meta.py</A>\r
480\r
481<DD>A generic metaclass. This is an attempt at finding out how much\r
482standard class behavior can be mimicked by a metaclass. The\r
483preliminary answer appears to be that everything's fine as long as the\r
484class (or its clients) don't look at the instance's __class__\r
485attribute, nor at the class's __dict__ attribute. The use of\r
486__getattr__ internally makes the classic implementation of __getattr__\r
487hooks tough; we provide a similar hook _getattr_ instead.\r
488(__setattr__ and __delattr__ are not affected.)\r
489(XXX Hm. Could detect presence of __getattr__ and rename it.)\r
490\r
491<P>\r
492\r
493<DT><A HREF="Eiffel.py">Eiffel.py</A>\r
494\r
495<DD>Uses the above generic metaclass to implement Eiffel style\r
496pre-conditions and post-conditions.\r
497\r
498<P>\r
499\r
500<DT><A HREF="Synch.py">Synch.py</A>\r
501\r
502<DD>Uses the above generic metaclass to implement synchronized\r
503methods.\r
504\r
505<P>\r
506\r
507<DT><A HREF="Simple.py">Simple.py</A>\r
508\r
509<DD>The example module used above.\r
510\r
511<P>\r
512\r
513</DL>\r
514\r
515<P>A pattern seems to be emerging: almost all these uses of\r
516metaclasses (except for Enum, which is probably more cute than useful)\r
517mostly work by placing wrappers around method calls. An obvious\r
518problem with that is that it's not easy to combine the features of\r
519different metaclasses, while this would actually be quite useful: for\r
520example, I wouldn't mind getting a trace from the test run of the\r
521Synch module, and it would be interesting to add preconditions to it\r
522as well. This needs more research. Perhaps a metaclass could be\r
523provided that allows stackable wrappers...\r
524\r
525<P>\r
526\r
527<HR>\r
528\r
529<H2>Things You Could Do With Metaclasses</H2>\r
530\r
531<P>There are lots of things you could do with metaclasses. Most of\r
532these can also be done with creative use of __getattr__, but\r
533metaclasses make it easier to modify the attribute lookup behavior of\r
534classes. Here's a partial list.\r
535\r
536<P>\r
537\r
538<UL>\r
539\r
540<LI>Enforce different inheritance semantics, e.g. automatically call\r
541base class methods when a derived class overrides<P>\r
542\r
543<LI>Implement class methods (e.g. if the first argument is not named\r
544'self')<P>\r
545\r
546<LI>Implement that each instance is initialized with <b>copies</b> of\r
547all class variables<P>\r
548\r
549<LI>Implement a different way to store instance variables (e.g. in a\r
550list kept outside the instance but indexed by the instance's id())<P>\r
551\r
552<LI>Automatically wrap or trap all or certain methods\r
553\r
554<UL>\r
555\r
556<LI>for tracing\r
557\r
558<LI>for precondition and postcondition checking\r
559\r
560<LI>for synchronized methods\r
561\r
562<LI>for automatic value caching\r
563\r
564</UL>\r
565<P>\r
566\r
567<LI>When an attribute is a parameterless function, call it on\r
568reference (to mimic it being an instance variable); same on assignment<P>\r
569\r
570<LI>Instrumentation: see how many times various attributes are used<P>\r
571\r
572<LI>Different semantics for __setattr__ and __getattr__ (e.g. disable\r
573them when they are being used recursively)<P>\r
574\r
575<LI>Abuse class syntax for other things<P>\r
576\r
577<LI>Experiment with automatic type checking<P>\r
578\r
579<LI>Delegation (or acquisition)<P>\r
580\r
581<LI>Dynamic inheritance patterns<P>\r
582\r
583<LI>Automatic caching of methods<P>\r
584\r
585</UL>\r
586\r
587<P>\r
588\r
589<HR>\r
590\r
591<H4>Credits</H4>\r
592\r
593<P>Many thanks to David Ascher and Donald Beaudry for their comments\r
594on earlier draft of this paper. Also thanks to Matt Conway and Tommy\r
595Burnette for putting a seed for the idea of metaclasses in my\r
596mind, nearly three years ago, even though at the time my response was\r
597``you can do that with __getattr__ hooks...'' :-)\r
598\r
599<P>\r
600\r
601<HR>\r
602\r
603</BODY>\r
604\r
605</HTML>\r