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