blob: e72567dabe6d24506ad4405a23c423fb2f90088d [file] [log] [blame]
Tim Peters95c99e52001-09-03 01:24:30 +00001# This contains most of the executable examples from Guido's descr
2# tutorial, once at
3#
4# http://www.python.org/2.2/descrintro.html
5#
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.
10
11from test_support import sortdict
12import pprint
13
14class defaultdict(dictionary):
15 def __init__(self, default=None):
16 dictionary.__init__(self)
17 self.default = default
18
19 def __getitem__(self, key):
20 try:
21 return dictionary.__getitem__(self, key)
22 except KeyError:
23 return self.default
24
25 def get(self, key, *args):
26 if not args:
27 args = (self.default,)
28 return dictionary.get(self, key, *args)
29
30 def merge(self, other):
31 for key in other:
32 if key not in self:
33 self[key] = other[key]
34
35test_1 = """
36
37Here's the new type at work:
38
39 >>> print defaultdict # show our type
Tim Peters90ba8d92001-09-09 01:21:31 +000040 <type 'test.test_descrtut.defaultdict'>
Tim Peters95c99e52001-09-03 01:24:30 +000041 >>> print type(defaultdict) # its metatype
42 <type 'type'>
43 >>> a = defaultdict(default=0.0) # create an instance
44 >>> print a # show the instance
45 {}
46 >>> print type(a) # show its type
Tim Peters90ba8d92001-09-09 01:21:31 +000047 <type 'test.test_descrtut.defaultdict'>
Tim Peters95c99e52001-09-03 01:24:30 +000048 >>> print a.__class__ # show its class
Tim Peters90ba8d92001-09-09 01:21:31 +000049 <type 'test.test_descrtut.defaultdict'>
Tim Peters95c99e52001-09-03 01:24:30 +000050 >>> print type(a) is a.__class__ # its type is its class
51 1
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 dictionary method
60 >>> print sortdict(a) # show the result
61 {1: 3.25, 2: 200}
62 >>>
63
64We can also use the new type in contexts where classic only allows "real"
65dictionaries, such as the locals/globals dictionaries for the exec
66statement or the built-in function eval():
67
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
74 3
75 >>> print sorted(a.keys())
76 [1, 2, '__builtins__', 'x']
77 >>> print a['x']
78 3
79 >>>
80
81However, our __getitem__() method is not used for variable access by the
82interpreter:
83
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 >>>
90
91Now I'll show that defaultdict instances have dynamic instance variables,
92just like classic classes:
93
94 >>> a.default = -1
95 >>> print a["noway"]
96 -1
97 >>> a.default = -1000
98 >>> print a["noway"]
99 -1000
Tim Peters5d2b77c2001-09-03 05:47:38 +0000100 >>> 'default' in dir(a)
101 1
Tim Peters95c99e52001-09-03 01:24:30 +0000102 >>> a.x1 = 100
103 >>> a.x2 = 200
104 >>> print a.x1
105 100
Tim Peters5d2b77c2001-09-03 05:47:38 +0000106 >>> d = dir(a)
107 >>> 'default' in d and 'x1' in d and 'x2' in d
108 1
Tim Peters95c99e52001-09-03 01:24:30 +0000109 >>> print a.__dict__
110 {'default': -1000, 'x2': 200, 'x1': 100}
111 >>>
112"""
113
114class defaultdict2(dictionary):
115 __slots__ = ['default']
116
117 def __init__(self, default=None):
118 dictionary.__init__(self)
119 self.default = default
120
121 def __getitem__(self, key):
122 try:
123 return dictionary.__getitem__(self, key)
124 except KeyError:
125 return self.default
126
127 def get(self, key, *args):
128 if not args:
129 args = (self.default,)
130 return dictionary.get(self, key, *args)
131
132 def merge(self, other):
133 for key in other:
134 if key not in self:
135 self[key] = other[key]
136
137test_2 = """
138
139The __slots__ declaration takes a list of instance variables, and reserves
140space for exactly these in the instance. When __slots__ is used, other
141instance variables cannot be assigned to:
142
143 >>> a = defaultdict2(default=0.0)
144 >>> a[1]
145 0.0
146 >>> a.default = -1
147 >>> a[1]
148 -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'
153 >>>
154
155"""
156
157test_3 = """
158
159Introspecting instances of built-in types
160
161For instance of built-in types, x.__class__ is now the same as type(x):
162
163 >>> type([])
164 <type 'list'>
165 >>> [].__class__
166 <type 'list'>
167 >>> list
168 <type 'list'>
169 >>> isinstance([], list)
170 1
171 >>> isinstance([], dictionary)
172 0
173 >>> isinstance([], object)
174 1
175 >>>
176
177Under the new proposal, the __methods__ attribute no longer exists:
178
179 >>> [].__methods__
180 Traceback (most recent call last):
181 File "<stdin>", line 1, in ?
182 AttributeError: 'list' object has no attribute '__methods__'
183 >>>
184
185Instead, you can get the same information from the list type:
186
187 >>> pprint.pprint(dir(list)) # like list.__dict__.keys(), but sorted
188 ['__add__',
189 '__class__',
190 '__contains__',
191 '__delattr__',
192 '__delitem__',
193 '__eq__',
194 '__ge__',
Guido van Rossum867a8d22001-09-21 19:29:08 +0000195 '__getattribute__',
Tim Peters95c99e52001-09-03 01:24:30 +0000196 '__getitem__',
197 '__getslice__',
198 '__gt__',
199 '__hash__',
200 '__iadd__',
201 '__imul__',
202 '__init__',
203 '__le__',
204 '__len__',
205 '__lt__',
206 '__mul__',
207 '__ne__',
208 '__new__',
209 '__repr__',
210 '__rmul__',
211 '__setattr__',
212 '__setitem__',
213 '__setslice__',
214 '__str__',
215 'append',
216 'count',
217 'extend',
218 'index',
219 'insert',
220 'pop',
221 'remove',
222 'reverse',
223 'sort']
224
225The new introspection API gives more information than the old one: in
226addition to the regular methods, it also shows the methods that are
227normally invoked through special notations, e.g. __iadd__ (+=), __len__
228(len), __ne__ (!=). You can invoke any method from this list directly:
229
230 >>> a = ['tic', 'tac']
231 >>> list.__len__(a) # same as len(a)
232 2
233 >>> a.__len__() # ditto
234 2
235 >>> list.append(a, 'toe') # same as a.append('toe')
236 >>> a
237 ['tic', 'tac', 'toe']
238 >>>
239
240This is just like it is for user-defined classes.
241"""
242
243test_4 = """
244
245Static methods and class methods
246
247The new introspection API makes it possible to add static methods and class
248methods. Static methods are easy to describe: they behave pretty much like
249static methods in C++ or Java. Here's an example:
250
251 >>> class C:
252 ...
253 ... def foo(x, y):
254 ... print "staticmethod", x, y
255 ... foo = staticmethod(foo)
256
257 >>> C.foo(1, 2)
258 staticmethod 1 2
259 >>> c = C()
260 >>> c.foo(1, 2)
261 staticmethod 1 2
262
263Class methods use a similar pattern to declare methods that receive an
264implicit first argument that is the *class* for which they are invoked.
265
266 >>> class C:
267 ... def foo(cls, y):
268 ... print "classmethod", cls, y
269 ... foo = classmethod(foo)
270
271 >>> C.foo(1)
Tim Peters90ba8d92001-09-09 01:21:31 +0000272 classmethod test.test_descrtut.C 1
Tim Peters95c99e52001-09-03 01:24:30 +0000273 >>> c = C()
274 >>> c.foo(1)
Tim Peters90ba8d92001-09-09 01:21:31 +0000275 classmethod test.test_descrtut.C 1
Tim Peters95c99e52001-09-03 01:24:30 +0000276
277 >>> class D(C):
278 ... pass
279
280 >>> D.foo(1)
Tim Peters90ba8d92001-09-09 01:21:31 +0000281 classmethod test.test_descrtut.D 1
Tim Peters95c99e52001-09-03 01:24:30 +0000282 >>> d = D()
283 >>> d.foo(1)
Tim Peters90ba8d92001-09-09 01:21:31 +0000284 classmethod test.test_descrtut.D 1
Tim Peters95c99e52001-09-03 01:24:30 +0000285
286This prints "classmethod __main__.D 1" both times; in other words, the
287class passed as the first argument of foo() is the class involved in the
288call, not the class involved in the definition of foo().
289
290But notice this:
291
292 >>> class E(C):
293 ... def foo(cls, y): # override C.foo
294 ... print "E.foo() called"
295 ... C.foo(y)
296 ... foo = classmethod(foo)
297
298 >>> E.foo(1)
299 E.foo() called
Tim Peters90ba8d92001-09-09 01:21:31 +0000300 classmethod test.test_descrtut.C 1
Tim Peters95c99e52001-09-03 01:24:30 +0000301 >>> e = E()
302 >>> e.foo(1)
303 E.foo() called
Tim Peters90ba8d92001-09-09 01:21:31 +0000304 classmethod test.test_descrtut.C 1
Tim Peters95c99e52001-09-03 01:24:30 +0000305
306In this example, the call to C.foo() from E.foo() will see class C as its
307first argument, not class E. This is to be expected, since the call
308specifies the class C. But it stresses the difference between these class
309methods and methods defined in metaclasses (where an upcall to a metamethod
310would pass the target class as an explicit first argument).
311"""
312
313test_5 = """
314
315Attributes defined by get/set methods
316
317
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000318 >>> class property(object):
Tim Peters95c99e52001-09-03 01:24:30 +0000319 ...
320 ... def __init__(self, get, set=None):
321 ... self.__get = get
322 ... self.__set = set
323 ...
324 ... def __get__(self, inst, type=None):
325 ... return self.__get(inst)
326 ...
327 ... def __set__(self, inst, value):
328 ... if self.__set is None:
329 ... raise AttributeError, "this attribute is read-only"
330 ... return self.__set(inst, value)
331
332Now let's define a class with an attribute x defined by a pair of methods,
333getx() and and setx():
334
335 >>> class C(object):
336 ...
337 ... def __init__(self):
338 ... self.__x = 0
339 ...
340 ... def getx(self):
341 ... return self.__x
342 ...
343 ... def setx(self, x):
344 ... if x < 0: x = 0
345 ... self.__x = x
346 ...
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000347 ... x = property(getx, setx)
Tim Peters95c99e52001-09-03 01:24:30 +0000348
349Here's a small demonstration:
350
351 >>> a = C()
352 >>> a.x = 10
353 >>> print a.x
354 10
355 >>> a.x = -10
356 >>> print a.x
357 0
358 >>>
359
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000360Hmm -- property is builtin now, so let's try it that way too.
Tim Peters95c99e52001-09-03 01:24:30 +0000361
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000362 >>> del property # unmask the builtin
363 >>> property
364 <type 'property'>
Tim Peters95c99e52001-09-03 01:24:30 +0000365
366 >>> class C(object):
367 ... def __init__(self):
368 ... self.__x = 0
369 ... def getx(self):
370 ... return self.__x
371 ... def setx(self, x):
372 ... if x < 0: x = 0
373 ... self.__x = x
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000374 ... x = property(getx, setx)
Tim Peters95c99e52001-09-03 01:24:30 +0000375
376
377 >>> a = C()
378 >>> a.x = 10
379 >>> print a.x
380 10
381 >>> a.x = -10
382 >>> print a.x
383 0
384 >>>
385"""
386
387test_6 = """
388
389Method resolution order
390
391This example is implicit in the writeup.
392
393>>> class A: # classic class
394... def save(self):
395... print "called A.save()"
396>>> class B(A):
397... pass
398>>> class C(A):
399... def save(self):
400... print "called C.save()"
401>>> class D(B, C):
402... pass
403
404>>> D().save()
405called A.save()
406
407>>> class A(object): # new class
408... def save(self):
409... print "called A.save()"
410>>> class B(A):
411... pass
412>>> class C(A):
413... def save(self):
414... print "called C.save()"
415>>> class D(B, C):
416... pass
417
418>>> D().save()
419called C.save()
420"""
421
422class A(object):
423 def m(self):
424 return "A"
425
426class B(A):
427 def m(self):
428 return "B" + super(B, self).m()
429
430class C(A):
431 def m(self):
432 return "C" + super(C, self).m()
433
434class D(C, B):
435 def m(self):
436 return "D" + super(D, self).m()
437
438
439test_7 = """
440
441Cooperative methods and "super"
442
443>>> print D().m() # "DCBA"
444DCBA
445"""
446
447test_8 = """
448
449Backwards incompatibilities
450
451>>> class A:
452... def foo(self):
453... print "called A.foo()"
454
455>>> class B(A):
456... pass
457
458>>> class C(A):
459... def foo(self):
460... B.foo(self)
461
462>>> C().foo()
463Traceback (most recent call last):
464 ...
465TypeError: unbound method foo() must be called with B instance as first argument (got C instance instead)
466
467>>> class C(A):
468... def foo(self):
469... A.foo(self)
470>>> C().foo()
471called A.foo()
472"""
473
474__test__ = {"tut1": test_1,
475 "tut2": test_2,
476 "tut3": test_3,
477 "tut4": test_4,
478 "tut5": test_5,
479 "tut6": test_6,
480 "tut7": test_7,
481 "tut8": test_8}
482
483# Magic test name that regrtest.py invokes *after* importing this module.
484# This worms around a bootstrap problem.
485# Note that doctest and regrtest both look in sys.argv for a "-v" argument,
486# so this works as expected in both ways of running regrtest.
Tim Petersa0a62222001-09-09 06:12:01 +0000487def test_main(verbose=None):
488 # Obscure: import this module as test.test_descrtut instead of as
489 # plain test_descrtut because the name of this module works its way
490 # into the doctest examples, and unless the full test.test_descrtut
491 # business is used the name can change depending on how the test is
492 # invoked.
493 import test_support, test.test_descrtut
494 test_support.run_doctest(test.test_descrtut, verbose)
Tim Peters95c99e52001-09-03 01:24:30 +0000495
496# This part isn't needed for regrtest, but for running the test directly.
497if __name__ == "__main__":
Tim Petersa0a62222001-09-09 06:12:01 +0000498 test_main(1)