Maintain backwards compatibility with python < 2.3 by dynamically
[python/dscho.git] / Lib / test / test_descrtut.py
blob5fa089790e50a7b3f71d95b60507e3295526f671
1 # This contains most of the executable examples from Guido's descr
2 # tutorial, once at
4 # http://www.python.org/2.2/descrintro.html
6 # A few examples left implicit in the writeup were fleshed out, a few were
7 # skipped due to lack of interest (e.g., faking super() by hand isn't
8 # of much interest anymore), and a few were fiddled to make the output
9 # deterministic.
11 from test.test_support import sortdict
12 import pprint
14 class defaultdict(dict):
15 def __init__(self, default=None):
16 dict.__init__(self)
17 self.default = default
19 def __getitem__(self, key):
20 try:
21 return dict.__getitem__(self, key)
22 except KeyError:
23 return self.default
25 def get(self, key, *args):
26 if not args:
27 args = (self.default,)
28 return dict.get(self, key, *args)
30 def merge(self, other):
31 for key in other:
32 if key not in self:
33 self[key] = other[key]
35 test_1 = """
37 Here's the new type at work:
39 >>> print defaultdict # show our type
40 <class 'test.test_descrtut.defaultdict'>
41 >>> print type(defaultdict) # its metatype
42 <type 'type'>
43 >>> a = defaultdict(default=0.0) # create an instance
44 >>> print a # show the instance
46 >>> print type(a) # show its type
47 <class 'test.test_descrtut.defaultdict'>
48 >>> print a.__class__ # show its class
49 <class 'test.test_descrtut.defaultdict'>
50 >>> print type(a) is a.__class__ # its type is its class
51 True
52 >>> a[1] = 3.25 # modify the instance
53 >>> print a # show the new value
54 {1: 3.25}
55 >>> print a[1] # show the new item
56 3.25
57 >>> print a[0] # a non-existant item
58 0.0
59 >>> a.merge({1:100, 2:200}) # use a dict method
60 >>> print sortdict(a) # show the result
61 {1: 3.25, 2: 200}
62 >>>
64 We can also use the new type in contexts where classic only allows "real"
65 dictionaries, such as the locals/globals dictionaries for the exec
66 statement or the built-in function eval():
68 >>> def sorted(seq):
69 ... seq.sort()
70 ... return seq
71 >>> print sorted(a.keys())
72 [1, 2]
73 >>> exec "x = 3; print x" in a
75 >>> print sorted(a.keys())
76 [1, 2, '__builtins__', 'x']
77 >>> print a['x']
79 >>>
81 However, our __getitem__() method is not used for variable access by the
82 interpreter:
84 >>> exec "print foo" in a
85 Traceback (most recent call last):
86 File "<stdin>", line 1, in ?
87 File "<string>", line 1, in ?
88 NameError: name 'foo' is not defined
89 >>>
91 Now I'll show that defaultdict instances have dynamic instance variables,
92 just like classic classes:
94 >>> a.default = -1
95 >>> print a["noway"]
97 >>> a.default = -1000
98 >>> print a["noway"]
99 -1000
100 >>> 'default' in dir(a)
101 True
102 >>> a.x1 = 100
103 >>> a.x2 = 200
104 >>> print a.x1
106 >>> d = dir(a)
107 >>> 'default' in d and 'x1' in d and 'x2' in d
108 True
109 >>> print sortdict(a.__dict__)
110 {'default': -1000, 'x1': 100, 'x2': 200}
114 class defaultdict2(dict):
115 __slots__ = ['default']
117 def __init__(self, default=None):
118 dict.__init__(self)
119 self.default = default
121 def __getitem__(self, key):
122 try:
123 return dict.__getitem__(self, key)
124 except KeyError:
125 return self.default
127 def get(self, key, *args):
128 if not args:
129 args = (self.default,)
130 return dict.get(self, key, *args)
132 def merge(self, other):
133 for key in other:
134 if key not in self:
135 self[key] = other[key]
137 test_2 = """
139 The __slots__ declaration takes a list of instance variables, and reserves
140 space for exactly these in the instance. When __slots__ is used, other
141 instance variables cannot be assigned to:
143 >>> a = defaultdict2(default=0.0)
144 >>> a[1]
146 >>> a.default = -1
147 >>> a[1]
149 >>> a.x1 = 1
150 Traceback (most recent call last):
151 File "<stdin>", line 1, in ?
152 AttributeError: 'defaultdict2' object has no attribute 'x1'
157 test_3 = """
159 Introspecting instances of built-in types
161 For instance of built-in types, x.__class__ is now the same as type(x):
163 >>> type([])
164 <type 'list'>
165 >>> [].__class__
166 <type 'list'>
167 >>> list
168 <type 'list'>
169 >>> isinstance([], list)
170 True
171 >>> isinstance([], dict)
172 False
173 >>> isinstance([], object)
174 True
177 Under the new proposal, the __methods__ attribute no longer exists:
179 >>> [].__methods__
180 Traceback (most recent call last):
181 File "<stdin>", line 1, in ?
182 AttributeError: 'list' object has no attribute '__methods__'
185 Instead, you can get the same information from the list type:
187 >>> pprint.pprint(dir(list)) # like list.__dict__.keys(), but sorted
188 ['__add__',
189 '__class__',
190 '__contains__',
191 '__delattr__',
192 '__delitem__',
193 '__delslice__',
194 '__doc__',
195 '__eq__',
196 '__ge__',
197 '__getattribute__',
198 '__getitem__',
199 '__getslice__',
200 '__gt__',
201 '__hash__',
202 '__iadd__',
203 '__imul__',
204 '__init__',
205 '__iter__',
206 '__le__',
207 '__len__',
208 '__lt__',
209 '__mul__',
210 '__ne__',
211 '__new__',
212 '__reduce__',
213 '__reduce_ex__',
214 '__repr__',
215 '__rmul__',
216 '__setattr__',
217 '__setitem__',
218 '__setslice__',
219 '__str__',
220 'append',
221 'count',
222 'extend',
223 'index',
224 'insert',
225 'pop',
226 'remove',
227 'reverse',
228 'sort']
230 The new introspection API gives more information than the old one: in
231 addition to the regular methods, it also shows the methods that are
232 normally invoked through special notations, e.g. __iadd__ (+=), __len__
233 (len), __ne__ (!=). You can invoke any method from this list directly:
235 >>> a = ['tic', 'tac']
236 >>> list.__len__(a) # same as len(a)
238 >>> a.__len__() # ditto
240 >>> list.append(a, 'toe') # same as a.append('toe')
241 >>> a
242 ['tic', 'tac', 'toe']
245 This is just like it is for user-defined classes.
248 test_4 = """
250 Static methods and class methods
252 The new introspection API makes it possible to add static methods and class
253 methods. Static methods are easy to describe: they behave pretty much like
254 static methods in C++ or Java. Here's an example:
256 >>> class C:
258 ... def foo(x, y):
259 ... print "staticmethod", x, y
260 ... foo = staticmethod(foo)
262 >>> C.foo(1, 2)
263 staticmethod 1 2
264 >>> c = C()
265 >>> c.foo(1, 2)
266 staticmethod 1 2
268 Class methods use a similar pattern to declare methods that receive an
269 implicit first argument that is the *class* for which they are invoked.
271 >>> class C:
272 ... def foo(cls, y):
273 ... print "classmethod", cls, y
274 ... foo = classmethod(foo)
276 >>> C.foo(1)
277 classmethod test.test_descrtut.C 1
278 >>> c = C()
279 >>> c.foo(1)
280 classmethod test.test_descrtut.C 1
282 >>> class D(C):
283 ... pass
285 >>> D.foo(1)
286 classmethod test.test_descrtut.D 1
287 >>> d = D()
288 >>> d.foo(1)
289 classmethod test.test_descrtut.D 1
291 This prints "classmethod __main__.D 1" both times; in other words, the
292 class passed as the first argument of foo() is the class involved in the
293 call, not the class involved in the definition of foo().
295 But notice this:
297 >>> class E(C):
298 ... def foo(cls, y): # override C.foo
299 ... print "E.foo() called"
300 ... C.foo(y)
301 ... foo = classmethod(foo)
303 >>> E.foo(1)
304 E.foo() called
305 classmethod test.test_descrtut.C 1
306 >>> e = E()
307 >>> e.foo(1)
308 E.foo() called
309 classmethod test.test_descrtut.C 1
311 In this example, the call to C.foo() from E.foo() will see class C as its
312 first argument, not class E. This is to be expected, since the call
313 specifies the class C. But it stresses the difference between these class
314 methods and methods defined in metaclasses (where an upcall to a metamethod
315 would pass the target class as an explicit first argument).
318 test_5 = """
320 Attributes defined by get/set methods
323 >>> class property(object):
325 ... def __init__(self, get, set=None):
326 ... self.__get = get
327 ... self.__set = set
329 ... def __get__(self, inst, type=None):
330 ... return self.__get(inst)
332 ... def __set__(self, inst, value):
333 ... if self.__set is None:
334 ... raise AttributeError, "this attribute is read-only"
335 ... return self.__set(inst, value)
337 Now let's define a class with an attribute x defined by a pair of methods,
338 getx() and and setx():
340 >>> class C(object):
342 ... def __init__(self):
343 ... self.__x = 0
345 ... def getx(self):
346 ... return self.__x
348 ... def setx(self, x):
349 ... if x < 0: x = 0
350 ... self.__x = x
352 ... x = property(getx, setx)
354 Here's a small demonstration:
356 >>> a = C()
357 >>> a.x = 10
358 >>> print a.x
360 >>> a.x = -10
361 >>> print a.x
365 Hmm -- property is builtin now, so let's try it that way too.
367 >>> del property # unmask the builtin
368 >>> property
369 <type 'property'>
371 >>> class C(object):
372 ... def __init__(self):
373 ... self.__x = 0
374 ... def getx(self):
375 ... return self.__x
376 ... def setx(self, x):
377 ... if x < 0: x = 0
378 ... self.__x = x
379 ... x = property(getx, setx)
382 >>> a = C()
383 >>> a.x = 10
384 >>> print a.x
386 >>> a.x = -10
387 >>> print a.x
392 test_6 = """
394 Method resolution order
396 This example is implicit in the writeup.
398 >>> class A: # classic class
399 ... def save(self):
400 ... print "called A.save()"
401 >>> class B(A):
402 ... pass
403 >>> class C(A):
404 ... def save(self):
405 ... print "called C.save()"
406 >>> class D(B, C):
407 ... pass
409 >>> D().save()
410 called A.save()
412 >>> class A(object): # new class
413 ... def save(self):
414 ... print "called A.save()"
415 >>> class B(A):
416 ... pass
417 >>> class C(A):
418 ... def save(self):
419 ... print "called C.save()"
420 >>> class D(B, C):
421 ... pass
423 >>> D().save()
424 called C.save()
427 class A(object):
428 def m(self):
429 return "A"
431 class B(A):
432 def m(self):
433 return "B" + super(B, self).m()
435 class C(A):
436 def m(self):
437 return "C" + super(C, self).m()
439 class D(C, B):
440 def m(self):
441 return "D" + super(D, self).m()
444 test_7 = """
446 Cooperative methods and "super"
448 >>> print D().m() # "DCBA"
449 DCBA
452 test_8 = """
454 Backwards incompatibilities
456 >>> class A:
457 ... def foo(self):
458 ... print "called A.foo()"
460 >>> class B(A):
461 ... pass
463 >>> class C(A):
464 ... def foo(self):
465 ... B.foo(self)
467 >>> C().foo()
468 Traceback (most recent call last):
470 TypeError: unbound method foo() must be called with B instance as first argument (got C instance instead)
472 >>> class C(A):
473 ... def foo(self):
474 ... A.foo(self)
475 >>> C().foo()
476 called A.foo()
479 __test__ = {"tut1": test_1,
480 "tut2": test_2,
481 "tut3": test_3,
482 "tut4": test_4,
483 "tut5": test_5,
484 "tut6": test_6,
485 "tut7": test_7,
486 "tut8": test_8}
488 # Magic test name that regrtest.py invokes *after* importing this module.
489 # This worms around a bootstrap problem.
490 # Note that doctest and regrtest both look in sys.argv for a "-v" argument,
491 # so this works as expected in both ways of running regrtest.
492 def test_main(verbose=None):
493 # Obscure: import this module as test.test_descrtut instead of as
494 # plain test_descrtut because the name of this module works its way
495 # into the doctest examples, and unless the full test.test_descrtut
496 # business is used the name can change depending on how the test is
497 # invoked.
498 from test import test_support, test_descrtut
499 test_support.run_doctest(test_descrtut, verbose)
501 # This part isn't needed for regrtest, but for running the test directly.
502 if __name__ == "__main__":
503 test_main(1)