test_descrtut.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. # This contains most of the executable examples from Guido's descr
  2. # tutorial, once at
  3. #
  4. # https://www.python.org/download/releases/2.2.3/descrintro/
  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. from test.support import sortdict
  11. import pprint
  12. import doctest
  13. import unittest
  14. class defaultdict(dict):
  15. def __init__(self, default=None):
  16. dict.__init__(self)
  17. self.default = default
  18. def __getitem__(self, key):
  19. try:
  20. return dict.__getitem__(self, key)
  21. except KeyError:
  22. return self.default
  23. def get(self, key, *args):
  24. if not args:
  25. args = (self.default,)
  26. return dict.get(self, key, *args)
  27. def merge(self, other):
  28. for key in other:
  29. if key not in self:
  30. self[key] = other[key]
  31. test_1 = """
  32. Here's the new type at work:
  33. >>> print(defaultdict) # show our type
  34. <class 'test.test_descrtut.defaultdict'>
  35. >>> print(type(defaultdict)) # its metatype
  36. <class 'type'>
  37. >>> a = defaultdict(default=0.0) # create an instance
  38. >>> print(a) # show the instance
  39. {}
  40. >>> print(type(a)) # show its type
  41. <class 'test.test_descrtut.defaultdict'>
  42. >>> print(a.__class__) # show its class
  43. <class 'test.test_descrtut.defaultdict'>
  44. >>> print(type(a) is a.__class__) # its type is its class
  45. True
  46. >>> a[1] = 3.25 # modify the instance
  47. >>> print(a) # show the new value
  48. {1: 3.25}
  49. >>> print(a[1]) # show the new item
  50. 3.25
  51. >>> print(a[0]) # a non-existent item
  52. 0.0
  53. >>> a.merge({1:100, 2:200}) # use a dict method
  54. >>> print(sortdict(a)) # show the result
  55. {1: 3.25, 2: 200}
  56. >>>
  57. We can also use the new type in contexts where classic only allows "real"
  58. dictionaries, such as the locals/globals dictionaries for the exec
  59. statement or the built-in function eval():
  60. >>> print(sorted(a.keys()))
  61. [1, 2]
  62. >>> a['print'] = print # need the print function here
  63. >>> exec("x = 3; print(x)", a)
  64. 3
  65. >>> print(sorted(a.keys(), key=lambda x: (str(type(x)), x)))
  66. [1, 2, '__builtins__', 'print', 'x']
  67. >>> print(a['x'])
  68. 3
  69. >>>
  70. Now I'll show that defaultdict instances have dynamic instance variables,
  71. just like classic classes:
  72. >>> a.default = -1
  73. >>> print(a["noway"])
  74. -1
  75. >>> a.default = -1000
  76. >>> print(a["noway"])
  77. -1000
  78. >>> 'default' in dir(a)
  79. True
  80. >>> a.x1 = 100
  81. >>> a.x2 = 200
  82. >>> print(a.x1)
  83. 100
  84. >>> d = dir(a)
  85. >>> 'default' in d and 'x1' in d and 'x2' in d
  86. True
  87. >>> print(sortdict(a.__dict__))
  88. {'default': -1000, 'x1': 100, 'x2': 200}
  89. >>>
  90. """
  91. class defaultdict2(dict):
  92. __slots__ = ['default']
  93. def __init__(self, default=None):
  94. dict.__init__(self)
  95. self.default = default
  96. def __getitem__(self, key):
  97. try:
  98. return dict.__getitem__(self, key)
  99. except KeyError:
  100. return self.default
  101. def get(self, key, *args):
  102. if not args:
  103. args = (self.default,)
  104. return dict.get(self, key, *args)
  105. def merge(self, other):
  106. for key in other:
  107. if key not in self:
  108. self[key] = other[key]
  109. test_2 = """
  110. The __slots__ declaration takes a list of instance variables, and reserves
  111. space for exactly these in the instance. When __slots__ is used, other
  112. instance variables cannot be assigned to:
  113. >>> a = defaultdict2(default=0.0)
  114. >>> a[1]
  115. 0.0
  116. >>> a.default = -1
  117. >>> a[1]
  118. -1
  119. >>> a.x1 = 1
  120. Traceback (most recent call last):
  121. File "<stdin>", line 1, in ?
  122. AttributeError: 'defaultdict2' object has no attribute 'x1'
  123. >>>
  124. """
  125. test_3 = """
  126. Introspecting instances of built-in types
  127. For instance of built-in types, x.__class__ is now the same as type(x):
  128. >>> type([])
  129. <class 'list'>
  130. >>> [].__class__
  131. <class 'list'>
  132. >>> list
  133. <class 'list'>
  134. >>> isinstance([], list)
  135. True
  136. >>> isinstance([], dict)
  137. False
  138. >>> isinstance([], object)
  139. True
  140. >>>
  141. You can get the information from the list type:
  142. >>> pprint.pprint(dir(list)) # like list.__dict__.keys(), but sorted
  143. ['__add__',
  144. '__class__',
  145. '__class_getitem__',
  146. '__contains__',
  147. '__delattr__',
  148. '__delitem__',
  149. '__dir__',
  150. '__doc__',
  151. '__eq__',
  152. '__format__',
  153. '__ge__',
  154. '__getattribute__',
  155. '__getitem__',
  156. '__getstate__',
  157. '__gt__',
  158. '__hash__',
  159. '__iadd__',
  160. '__imul__',
  161. '__init__',
  162. '__init_subclass__',
  163. '__iter__',
  164. '__le__',
  165. '__len__',
  166. '__lt__',
  167. '__mul__',
  168. '__ne__',
  169. '__new__',
  170. '__reduce__',
  171. '__reduce_ex__',
  172. '__repr__',
  173. '__reversed__',
  174. '__rmul__',
  175. '__setattr__',
  176. '__setitem__',
  177. '__sizeof__',
  178. '__str__',
  179. '__subclasshook__',
  180. 'append',
  181. 'clear',
  182. 'copy',
  183. 'count',
  184. 'extend',
  185. 'index',
  186. 'insert',
  187. 'pop',
  188. 'remove',
  189. 'reverse',
  190. 'sort']
  191. The new introspection API gives more information than the old one: in
  192. addition to the regular methods, it also shows the methods that are
  193. normally invoked through special notations, e.g. __iadd__ (+=), __len__
  194. (len), __ne__ (!=). You can invoke any method from this list directly:
  195. >>> a = ['tic', 'tac']
  196. >>> list.__len__(a) # same as len(a)
  197. 2
  198. >>> a.__len__() # ditto
  199. 2
  200. >>> list.append(a, 'toe') # same as a.append('toe')
  201. >>> a
  202. ['tic', 'tac', 'toe']
  203. >>>
  204. This is just like it is for user-defined classes.
  205. """
  206. test_4 = """
  207. Static methods and class methods
  208. The new introspection API makes it possible to add static methods and class
  209. methods. Static methods are easy to describe: they behave pretty much like
  210. static methods in C++ or Java. Here's an example:
  211. >>> class C:
  212. ...
  213. ... @staticmethod
  214. ... def foo(x, y):
  215. ... print("staticmethod", x, y)
  216. >>> C.foo(1, 2)
  217. staticmethod 1 2
  218. >>> c = C()
  219. >>> c.foo(1, 2)
  220. staticmethod 1 2
  221. Class methods use a similar pattern to declare methods that receive an
  222. implicit first argument that is the *class* for which they are invoked.
  223. >>> class C:
  224. ... @classmethod
  225. ... def foo(cls, y):
  226. ... print("classmethod", cls, y)
  227. >>> C.foo(1)
  228. classmethod <class 'test.test_descrtut.C'> 1
  229. >>> c = C()
  230. >>> c.foo(1)
  231. classmethod <class 'test.test_descrtut.C'> 1
  232. >>> class D(C):
  233. ... pass
  234. >>> D.foo(1)
  235. classmethod <class 'test.test_descrtut.D'> 1
  236. >>> d = D()
  237. >>> d.foo(1)
  238. classmethod <class 'test.test_descrtut.D'> 1
  239. This prints "classmethod __main__.D 1" both times; in other words, the
  240. class passed as the first argument of foo() is the class involved in the
  241. call, not the class involved in the definition of foo().
  242. But notice this:
  243. >>> class E(C):
  244. ... @classmethod
  245. ... def foo(cls, y): # override C.foo
  246. ... print("E.foo() called")
  247. ... C.foo(y)
  248. >>> E.foo(1)
  249. E.foo() called
  250. classmethod <class 'test.test_descrtut.C'> 1
  251. >>> e = E()
  252. >>> e.foo(1)
  253. E.foo() called
  254. classmethod <class 'test.test_descrtut.C'> 1
  255. In this example, the call to C.foo() from E.foo() will see class C as its
  256. first argument, not class E. This is to be expected, since the call
  257. specifies the class C. But it stresses the difference between these class
  258. methods and methods defined in metaclasses (where an upcall to a metamethod
  259. would pass the target class as an explicit first argument).
  260. """
  261. test_5 = """
  262. Attributes defined by get/set methods
  263. >>> class property(object):
  264. ...
  265. ... def __init__(self, get, set=None):
  266. ... self.__get = get
  267. ... self.__set = set
  268. ...
  269. ... def __get__(self, inst, type=None):
  270. ... return self.__get(inst)
  271. ...
  272. ... def __set__(self, inst, value):
  273. ... if self.__set is None:
  274. ... raise AttributeError("this attribute is read-only")
  275. ... return self.__set(inst, value)
  276. Now let's define a class with an attribute x defined by a pair of methods,
  277. getx() and setx():
  278. >>> class C(object):
  279. ...
  280. ... def __init__(self):
  281. ... self.__x = 0
  282. ...
  283. ... def getx(self):
  284. ... return self.__x
  285. ...
  286. ... def setx(self, x):
  287. ... if x < 0: x = 0
  288. ... self.__x = x
  289. ...
  290. ... x = property(getx, setx)
  291. Here's a small demonstration:
  292. >>> a = C()
  293. >>> a.x = 10
  294. >>> print(a.x)
  295. 10
  296. >>> a.x = -10
  297. >>> print(a.x)
  298. 0
  299. >>>
  300. Hmm -- property is builtin now, so let's try it that way too.
  301. >>> del property # unmask the builtin
  302. >>> property
  303. <class 'property'>
  304. >>> class C(object):
  305. ... def __init__(self):
  306. ... self.__x = 0
  307. ... def getx(self):
  308. ... return self.__x
  309. ... def setx(self, x):
  310. ... if x < 0: x = 0
  311. ... self.__x = x
  312. ... x = property(getx, setx)
  313. >>> a = C()
  314. >>> a.x = 10
  315. >>> print(a.x)
  316. 10
  317. >>> a.x = -10
  318. >>> print(a.x)
  319. 0
  320. >>>
  321. """
  322. test_6 = """
  323. Method resolution order
  324. This example is implicit in the writeup.
  325. >>> class A: # implicit new-style class
  326. ... def save(self):
  327. ... print("called A.save()")
  328. >>> class B(A):
  329. ... pass
  330. >>> class C(A):
  331. ... def save(self):
  332. ... print("called C.save()")
  333. >>> class D(B, C):
  334. ... pass
  335. >>> D().save()
  336. called C.save()
  337. >>> class A(object): # explicit new-style class
  338. ... def save(self):
  339. ... print("called A.save()")
  340. >>> class B(A):
  341. ... pass
  342. >>> class C(A):
  343. ... def save(self):
  344. ... print("called C.save()")
  345. >>> class D(B, C):
  346. ... pass
  347. >>> D().save()
  348. called C.save()
  349. """
  350. class A(object):
  351. def m(self):
  352. return "A"
  353. class B(A):
  354. def m(self):
  355. return "B" + super(B, self).m()
  356. class C(A):
  357. def m(self):
  358. return "C" + super(C, self).m()
  359. class D(C, B):
  360. def m(self):
  361. return "D" + super(D, self).m()
  362. test_7 = """
  363. Cooperative methods and "super"
  364. >>> print(D().m()) # "DCBA"
  365. DCBA
  366. """
  367. test_8 = """
  368. Backwards incompatibilities
  369. >>> class A:
  370. ... def foo(self):
  371. ... print("called A.foo()")
  372. >>> class B(A):
  373. ... pass
  374. >>> class C(A):
  375. ... def foo(self):
  376. ... B.foo(self)
  377. >>> C().foo()
  378. called A.foo()
  379. >>> class C(A):
  380. ... def foo(self):
  381. ... A.foo(self)
  382. >>> C().foo()
  383. called A.foo()
  384. """
  385. __test__ = {"tut1": test_1,
  386. "tut2": test_2,
  387. "tut3": test_3,
  388. "tut4": test_4,
  389. "tut5": test_5,
  390. "tut6": test_6,
  391. "tut7": test_7,
  392. "tut8": test_8}
  393. def load_tests(loader, tests, pattern):
  394. tests.addTest(doctest.DocTestSuite())
  395. return tests
  396. if __name__ == "__main__":
  397. unittest.main()