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