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