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