Guido van Rossum | a9ca42d | 1998-08-10 01:56:14 +0000 | [diff] [blame] | 1 | Subject: Re: The metaclass saga using Python |
| 2 | From: Vladimir Marangozov <Vladimir.Marangozov@imag.fr> |
| 3 | To: tim_one@email.msn.com (Tim Peters) |
| 4 | Cc: python-list@cwi.nl |
| 5 | Date: Wed, 5 Aug 1998 15:59:06 +0200 (DFT) |
| 6 | |
| 7 | [Tim] |
| 8 | > |
| 9 | > building-on-examples-tends-to-prevent-abstract-thrashing-ly y'rs - tim |
| 10 | > |
| 11 | |
| 12 | OK, I stand corrected. I understand that anybody's interpretation of |
| 13 | the meta-class concept is likely to be difficult to digest by others. |
| 14 | |
| 15 | Here's another try, expressing the same thing, but using the Python |
| 16 | programming model, examples and, perhaps, more popular terms. |
| 17 | |
| 18 | 1. Classes. |
| 19 | |
| 20 | This is pure Python of today. Sorry about the tutorial, but it is |
| 21 | meant to illustrate the second part, which is the one we're |
| 22 | interested in and which will follow the same development scenario. |
| 23 | Besides, newbies are likely to understand that the discussion is |
| 24 | affordable even for them :-) |
| 25 | |
| 26 | a) Class definition |
| 27 | |
| 28 | A class is meant to define the common properties of a set of objects. |
| 29 | A class is a "package" of properties. The assembly of properties |
| 30 | in a class package is sometimes called a class structure (which isn't |
| 31 | always appropriate). |
| 32 | |
| 33 | >>> class A: |
| 34 | attr1 = "Hello" # an attribute of A |
| 35 | def method1(self, *args): pass # method1 of A |
| 36 | def method2(self, *args): pass # method2 of A |
| 37 | >>> |
| 38 | |
| 39 | So far, we defined the structure of the class A. The class A is |
| 40 | of type <class>. We can check this by asking Python: "what is A?" |
| 41 | |
| 42 | >>> A # What is A? |
| 43 | <class __main__.A at 2023e360> |
| 44 | |
Guido van Rossum | 482e82a | 1998-08-10 13:18:11 +0000 | [diff] [blame] | 45 | b) Class instantiation |
Guido van Rossum | a9ca42d | 1998-08-10 01:56:14 +0000 | [diff] [blame] | 46 | |
| 47 | Creating an object with the properties defined in the class A is |
Guido van Rossum | 482e82a | 1998-08-10 13:18:11 +0000 | [diff] [blame] | 48 | called instantiation of the class A. After an instantiation of A, we |
Guido van Rossum | a9ca42d | 1998-08-10 01:56:14 +0000 | [diff] [blame] | 49 | obtain a new object, called an instance, which has the properties |
| 50 | packaged in the class A. |
| 51 | |
| 52 | >>> a = A() # 'a' is the 1st instance of A |
| 53 | >>> a # What is 'a'? |
| 54 | <__main__.A instance at 2022b9d0> |
| 55 | |
| 56 | >>> b = A() # 'b' is another instance of A |
| 57 | >>> b # What is 'b'? |
| 58 | <__main__.A instance at 2022b9c0> |
| 59 | |
| 60 | The objects, 'a' and 'b', are of type <instance> and they both have |
| 61 | the same properties. Note, that 'a' and 'b' are different objects. |
| 62 | (their adresses differ). This is a bit hard to see, so let's ask Python: |
| 63 | |
| 64 | >>> a == b # Is 'a' the same object as 'b'? |
| 65 | 0 # No. |
| 66 | |
| 67 | Instance objects have one more special property, indicating the class |
| 68 | they are an instance of. This property is named __class__. |
| 69 | |
| 70 | >>> a.__class__ # What is the class of 'a'? |
| 71 | <class __main__.A at 2023e360> # 'a' is an instance of A |
| 72 | >>> b.__class__ # What is the class of 'b'? |
| 73 | <class __main__.A at 2023e360> # 'b' is an instance of A |
| 74 | >>> a.__class__ == b.__class__ # Is it really the same class A? |
| 75 | 1 # Yes. |
| 76 | |
| 77 | c) Class inheritance (class composition and specialization) |
| 78 | |
| 79 | Classes can be defined in terms of other existing classes (and only |
| 80 | classes! -- don't bug me on this now). Thus, we can compose property |
| 81 | packages and create new ones. We reuse the property set defined |
| 82 | in a class by defining a new class, which "inherits" from the former. |
| 83 | In other words, a class B which inherits from the class A, inherits |
| 84 | the properties defined in A, or, B inherits the structure of A. |
| 85 | |
| 86 | In the same time, at the definition of the new class B, we can enrich |
| 87 | the inherited set of properties by adding new ones and/or modify some |
| 88 | of the inherited properties. |
| 89 | |
| 90 | >>> class B(A): # B inherits A's properties |
| 91 | attr2 = "World" # additional attr2 |
| 92 | def method2(self, arg1): pass # method2 is redefined |
| 93 | def method3(self, *args): pass # additional method3 |
| 94 | |
| 95 | >>> B # What is B? |
| 96 | <class __main__.B at 2023e500> |
| 97 | >>> B == A # Is B the same class as A? |
| 98 | 0 # No. |
| 99 | |
| 100 | Classes define one special property, indicating whether a class |
| 101 | inherits the properties of another class. This property is called |
| 102 | __bases__ and it contains a list (a tuple) of the classes the new |
| 103 | class inherits from. The classes from which a class is inheriting the |
| 104 | properties are called superclasses (in Python, we call them also -- |
| 105 | base classes). |
| 106 | |
| 107 | >>> A.__bases__ # Does A have any superclasses? |
| 108 | () # No. |
| 109 | >>> B.__bases__ # Does B have any superclasses? |
| 110 | (<class __main__.A at 2023e360>,) # Yes. It has one superclass. |
| 111 | >>> B.__bases__[0] == A # Is it really the class A? |
| 112 | 1 # Yes, it is. |
| 113 | |
| 114 | -------- |
| 115 | |
| 116 | Congratulations on getting this far! This was the hard part. |
| 117 | Now, let's continue with the easy one. |
| 118 | |
| 119 | -------- |
| 120 | |
| 121 | 2. Meta-classes |
| 122 | |
| 123 | You have to admit, that an anonymous group of Python wizards are |
| 124 | not satisfied with the property packaging facilities presented above. |
| 125 | They say, that the Real-World bugs them with problems that cannot be |
| 126 | modelled successfully with classes. Or, that the way classes are |
| 127 | implemented in Python and the way classes and instances behave at |
| 128 | runtime isn't always appropriate for reproducing the Real-World's |
| 129 | behavior in a way that satisfies them. |
| 130 | |
| 131 | Hence, what they want is the following: |
| 132 | |
| 133 | a) leave objects as they are (instances of classes) |
| 134 | b) leave classes as they are (property packages and object creators) |
| 135 | |
| 136 | BUT, at the same time: |
| 137 | |
| 138 | c) consider classes as being instances of mysterious objects. |
| 139 | d) label mysterious objects "meta-classes". |
| 140 | |
| 141 | Easy, eh? |
| 142 | |
| 143 | You may ask: "Why on earth do they want to do that?". |
| 144 | They answer: "Poor soul... Go and see how cruel the Real-World is!". |
| 145 | You - fuzzy: "OK, will do!" |
| 146 | |
| 147 | And here we go for another round of what I said in section 1 -- Classes. |
| 148 | |
| 149 | However, be warned! The features we're going to talk about aren't fully |
| 150 | implemented yet, because the Real-World don't let wizards to evaluate |
| 151 | precisely how cruel it is, so the features are still highly-experimental. |
| 152 | |
| 153 | a) Meta-class definition |
| 154 | |
| 155 | A meta-class is meant to define the common properties of a set of |
| 156 | classes. A meta-class is a "package" of properties. The assembly |
| 157 | of properties in a meta-class package is sometimes called a meta-class |
| 158 | structure (which isn't always appropriate). |
| 159 | |
| 160 | In Python, a meta-class definition would have looked like this: |
| 161 | |
| 162 | >>> metaclass M: |
| 163 | attr1 = "Hello" # an attribute of M |
| 164 | def method1(self, *args): pass # method1 of M |
| 165 | def method2(self, *args): pass # method2 of M |
| 166 | >>> |
| 167 | |
| 168 | So far, we defined the structure of the meta-class M. The meta-class |
| 169 | M is of type <metaclass>. We cannot check this by asking Python, but |
| 170 | if we could, it would have answered: |
| 171 | |
| 172 | >>> M # What is M? |
| 173 | <metaclass __main__.M at 2023e4e0> |
| 174 | |
Guido van Rossum | 482e82a | 1998-08-10 13:18:11 +0000 | [diff] [blame] | 175 | b) Meta-class instantiation |
Guido van Rossum | a9ca42d | 1998-08-10 01:56:14 +0000 | [diff] [blame] | 176 | |
| 177 | Creating an object with the properties defined in the meta-class M is |
Guido van Rossum | 482e82a | 1998-08-10 13:18:11 +0000 | [diff] [blame] | 178 | called instantiation of the meta-class M. After an instantiation of M, |
Guido van Rossum | a9ca42d | 1998-08-10 01:56:14 +0000 | [diff] [blame] | 179 | we obtain a new object, called an class, but now it is called also |
| 180 | a meta-instance, which has the properties packaged in the meta-class M. |
| 181 | |
| 182 | In Python, instantiating a meta-class would have looked like this: |
| 183 | |
| 184 | >>> A = M() # 'A' is the 1st instance of M |
| 185 | >>> A # What is 'A'? |
| 186 | <class __main__.A at 2022b9d0> |
| 187 | |
| 188 | >>> B = M() # 'B' is another instance of M |
| 189 | >>> B # What is 'B'? |
| 190 | <class __main__.B at 2022b9c0> |
| 191 | |
| 192 | The metaclass-instances, A and B, are of type <class> and they both |
| 193 | have the same properties. Note, that A and B are different objects. |
| 194 | (their adresses differ). This is a bit hard to see, but if it was |
| 195 | possible to ask Python, it would have answered: |
| 196 | |
| 197 | >>> A == B # Is A the same class as B? |
| 198 | 0 # No. |
| 199 | |
| 200 | Class objects have one more special property, indicating the meta-class |
| 201 | they are an instance of. This property is named __metaclass__. |
| 202 | |
| 203 | >>> A.__metaclass__ # What is the meta-class of A? |
| 204 | <metaclass __main__.M at 2023e4e0> # A is an instance of M |
| 205 | >>> A.__metaclass__ # What is the meta-class of B? |
| 206 | <metaclass __main__.M at 2023e4e0> # B is an instance of M |
| 207 | >>> A.__metaclass__ == B.__metaclass__ # Is it the same meta-class M? |
| 208 | 1 # Yes. |
| 209 | |
| 210 | c) Meta-class inheritance (meta-class composition and specialization) |
| 211 | |
| 212 | Meta-classes can be defined in terms of other existing meta-classes |
| 213 | (and only meta-classes!). Thus, we can compose property packages and |
| 214 | create new ones. We reuse the property set defined in a meta-class by |
| 215 | defining a new meta-class, which "inherits" from the former. |
| 216 | In other words, a meta-class N which inherits from the meta-class M, |
| 217 | inherits the properties defined in M, or, N inherits the structure of M. |
| 218 | |
| 219 | In the same time, at the definition of the new meta-class N, we can |
| 220 | enrich the inherited set of properties by adding new ones and/or modify |
| 221 | some of the inherited properties. |
| 222 | |
| 223 | >>> metaclass N(M): # N inherits M's properties |
| 224 | attr2 = "World" # additional attr2 |
| 225 | def method2(self, arg1): pass # method2 is redefined |
| 226 | def method3(self, *args): pass # additional method3 |
| 227 | |
| 228 | >>> N # What is N? |
| 229 | <metaclass __main__.N at 2023e500> |
| 230 | >>> N == M # Is N the same meta-class as M? |
| 231 | 0 # No. |
| 232 | |
| 233 | Meta-classes define one special property, indicating whether a |
| 234 | meta-class inherits the properties of another meta-class. This property |
| 235 | is called __metabases__ and it contains a list (a tuple) of the |
| 236 | meta-classes the new meta-class inherits from. The meta-classes from |
| 237 | which a meta-class is inheriting the properties are called |
| 238 | super-meta-classes (in Python, we call them also -- super meta-bases). |
| 239 | |
| 240 | >>> M.__metabases__ # Does M have any supermetaclasses? |
| 241 | () # No. |
| 242 | >>> N.__metabases__ # Does N have any supermetaclasses? |
| 243 | (<metaclass __main__.M at 2023e360>,) # Yes. It has a supermetaclass. |
Guido van Rossum | 482e82a | 1998-08-10 13:18:11 +0000 | [diff] [blame] | 244 | >>> N.__metabases__[0] == M # Is it really the meta-class M? |
Guido van Rossum | a9ca42d | 1998-08-10 01:56:14 +0000 | [diff] [blame] | 245 | 1 # Yes, it is. |
| 246 | |
| 247 | -------- |
| 248 | |
| 249 | Triple congratulations on getting this far! |
| 250 | Now you know everything about meta-classes and the Real-World! |
| 251 | |
| 252 | <unless-wizards-want-meta-classes-be-instances-of-mysterious-objects!> |
| 253 | |
| 254 | -- |
| 255 | Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr |
| 256 | http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 |