| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 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 |  | 
| Benjamin Peterson | ee8712c | 2008-05-20 21:35:26 +0000 | [diff] [blame] | 11 | from test.support import sortdict | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 12 | import pprint | 
|  | 13 |  | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 14 | class defaultdict(dict): | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 15 | def __init__(self, default=None): | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 16 | dict.__init__(self) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 17 | self.default = default | 
|  | 18 |  | 
|  | 19 | def __getitem__(self, key): | 
|  | 20 | try: | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 21 | return dict.__getitem__(self, key) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 22 | except KeyError: | 
|  | 23 | return self.default | 
|  | 24 |  | 
|  | 25 | def get(self, key, *args): | 
|  | 26 | if not args: | 
|  | 27 | args = (self.default,) | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 28 | return dict.get(self, key, *args) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 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 |  | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 39 | >>> print(defaultdict)              # show our type | 
| Guido van Rossum | a4cb788 | 2001-09-25 03:56:29 +0000 | [diff] [blame] | 40 | <class 'test.test_descrtut.defaultdict'> | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 41 | >>> print(type(defaultdict))        # its metatype | 
| Martin v. Löwis | 250ad61 | 2008-04-07 05:43:42 +0000 | [diff] [blame] | 42 | <class 'type'> | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 43 | >>> a = defaultdict(default=0.0)    # create an instance | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 44 | >>> print(a)                        # show the instance | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 45 | {} | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 46 | >>> print(type(a))                  # show its type | 
| Guido van Rossum | a4cb788 | 2001-09-25 03:56:29 +0000 | [diff] [blame] | 47 | <class 'test.test_descrtut.defaultdict'> | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 48 | >>> print(a.__class__)              # show its class | 
| Guido van Rossum | a4cb788 | 2001-09-25 03:56:29 +0000 | [diff] [blame] | 49 | <class 'test.test_descrtut.defaultdict'> | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 50 | >>> print(type(a) is a.__class__)   # its type is its class | 
| Guido van Rossum | 77f6a65 | 2002-04-03 22:41:51 +0000 | [diff] [blame] | 51 | True | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 52 | >>> a[1] = 3.25                     # modify the instance | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 53 | >>> print(a)                        # show the new value | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 54 | {1: 3.25} | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 55 | >>> print(a[1])                     # show the new item | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 56 | 3.25 | 
| Mark Dickinson | 934896d | 2009-02-21 20:59:32 +0000 | [diff] [blame] | 57 | >>> print(a[0])                     # a non-existent item | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 58 | 0.0 | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 59 | >>> a.merge({1:100, 2:200})         # use a dict method | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 60 | >>> print(sortdict(a))              # show the result | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 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 |  | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 68 | >>> print(sorted(a.keys())) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 69 | [1, 2] | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 70 | >>> a['print'] = print              # need the print function here | 
|  | 71 | >>> exec("x = 3; print(x)", a) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 72 | 3 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 73 | >>> print(sorted(a.keys(), key=lambda x: (str(type(x)), x))) | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 74 | [1, 2, '__builtins__', 'print', 'x'] | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 75 | >>> print(a['x']) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 76 | 3 | 
|  | 77 | >>> | 
|  | 78 |  | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 79 | Now I'll show that defaultdict instances have dynamic instance variables, | 
|  | 80 | just like classic classes: | 
|  | 81 |  | 
|  | 82 | >>> a.default = -1 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 83 | >>> print(a["noway"]) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 84 | -1 | 
|  | 85 | >>> a.default = -1000 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 86 | >>> print(a["noway"]) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 87 | -1000 | 
| Tim Peters | 5d2b77c | 2001-09-03 05:47:38 +0000 | [diff] [blame] | 88 | >>> 'default' in dir(a) | 
| Guido van Rossum | 77f6a65 | 2002-04-03 22:41:51 +0000 | [diff] [blame] | 89 | True | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 90 | >>> a.x1 = 100 | 
|  | 91 | >>> a.x2 = 200 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 92 | >>> print(a.x1) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 93 | 100 | 
| Tim Peters | 5d2b77c | 2001-09-03 05:47:38 +0000 | [diff] [blame] | 94 | >>> d = dir(a) | 
|  | 95 | >>> 'default' in d and 'x1' in d and 'x2' in d | 
| Guido van Rossum | 77f6a65 | 2002-04-03 22:41:51 +0000 | [diff] [blame] | 96 | True | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 97 | >>> print(sortdict(a.__dict__)) | 
| Tim Peters | e2052ab | 2003-02-18 16:54:41 +0000 | [diff] [blame] | 98 | {'default': -1000, 'x1': 100, 'x2': 200} | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 99 | >>> | 
|  | 100 | """ | 
|  | 101 |  | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 102 | class defaultdict2(dict): | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 103 | __slots__ = ['default'] | 
|  | 104 |  | 
|  | 105 | def __init__(self, default=None): | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 106 | dict.__init__(self) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 107 | self.default = default | 
|  | 108 |  | 
|  | 109 | def __getitem__(self, key): | 
|  | 110 | try: | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 111 | return dict.__getitem__(self, key) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 112 | except KeyError: | 
|  | 113 | return self.default | 
|  | 114 |  | 
|  | 115 | def get(self, key, *args): | 
|  | 116 | if not args: | 
|  | 117 | args = (self.default,) | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 118 | return dict.get(self, key, *args) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 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([]) | 
| Martin v. Löwis | 250ad61 | 2008-04-07 05:43:42 +0000 | [diff] [blame] | 152 | <class 'list'> | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 153 | >>> [].__class__ | 
| Martin v. Löwis | 250ad61 | 2008-04-07 05:43:42 +0000 | [diff] [blame] | 154 | <class 'list'> | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 155 | >>> list | 
| Martin v. Löwis | 250ad61 | 2008-04-07 05:43:42 +0000 | [diff] [blame] | 156 | <class 'list'> | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 157 | >>> isinstance([], list) | 
| Guido van Rossum | 77f6a65 | 2002-04-03 22:41:51 +0000 | [diff] [blame] | 158 | True | 
| Tim Peters | a427a2b | 2001-10-29 22:25:45 +0000 | [diff] [blame] | 159 | >>> isinstance([], dict) | 
| Guido van Rossum | 77f6a65 | 2002-04-03 22:41:51 +0000 | [diff] [blame] | 160 | False | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 161 | >>> isinstance([], object) | 
| Guido van Rossum | 77f6a65 | 2002-04-03 22:41:51 +0000 | [diff] [blame] | 162 | True | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 163 | >>> | 
|  | 164 |  | 
| Neal Norwitz | 8dfc4a9 | 2007-08-11 06:39:53 +0000 | [diff] [blame] | 165 | You can get the information from the list type: | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 166 |  | 
|  | 167 | >>> pprint.pprint(dir(list))    # like list.__dict__.keys(), but sorted | 
|  | 168 | ['__add__', | 
|  | 169 | '__class__', | 
|  | 170 | '__contains__', | 
|  | 171 | '__delattr__', | 
|  | 172 | '__delitem__', | 
| Tim Peters | 8044055 | 2002-02-19 04:25:19 +0000 | [diff] [blame] | 173 | '__doc__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 174 | '__eq__', | 
| Eric Smith | 8c66326 | 2007-08-25 02:26:07 +0000 | [diff] [blame] | 175 | '__format__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 176 | '__ge__', | 
| Guido van Rossum | 867a8d2 | 2001-09-21 19:29:08 +0000 | [diff] [blame] | 177 | '__getattribute__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 178 | '__getitem__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 179 | '__gt__', | 
|  | 180 | '__hash__', | 
|  | 181 | '__iadd__', | 
|  | 182 | '__imul__', | 
|  | 183 | '__init__', | 
| Raymond Hettinger | 14bd6de | 2002-05-31 21:40:38 +0000 | [diff] [blame] | 184 | '__iter__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 185 | '__le__', | 
|  | 186 | '__len__', | 
|  | 187 | '__lt__', | 
|  | 188 | '__mul__', | 
|  | 189 | '__ne__', | 
|  | 190 | '__new__', | 
| Guido van Rossum | 3926a63 | 2001-09-25 16:25:58 +0000 | [diff] [blame] | 191 | '__reduce__', | 
| Guido van Rossum | c53f009 | 2003-02-18 22:05:12 +0000 | [diff] [blame] | 192 | '__reduce_ex__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 193 | '__repr__', | 
| Raymond Hettinger | af28e4b | 2003-11-08 12:39:53 +0000 | [diff] [blame] | 194 | '__reversed__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 195 | '__rmul__', | 
|  | 196 | '__setattr__', | 
|  | 197 | '__setitem__', | 
| Martin v. Löwis | 00709aa | 2008-06-04 14:18:43 +0000 | [diff] [blame] | 198 | '__sizeof__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 199 | '__str__', | 
| Christian Heimes | 9e7f1d2 | 2008-02-28 12:27:11 +0000 | [diff] [blame] | 200 | '__subclasshook__', | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 201 | 'append', | 
|  | 202 | 'count', | 
|  | 203 | 'extend', | 
|  | 204 | 'index', | 
|  | 205 | 'insert', | 
|  | 206 | 'pop', | 
|  | 207 | 'remove', | 
|  | 208 | 'reverse', | 
| Raymond Hettinger | 64958a1 | 2003-12-17 20:43:33 +0000 | [diff] [blame] | 209 | 'sort'] | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 210 |  | 
|  | 211 | The new introspection API gives more information than the old one:  in | 
|  | 212 | addition to the regular methods, it also shows the methods that are | 
|  | 213 | normally invoked through special notations, e.g. __iadd__ (+=), __len__ | 
|  | 214 | (len), __ne__ (!=). You can invoke any method from this list directly: | 
|  | 215 |  | 
|  | 216 | >>> a = ['tic', 'tac'] | 
|  | 217 | >>> list.__len__(a)          # same as len(a) | 
|  | 218 | 2 | 
|  | 219 | >>> a.__len__()              # ditto | 
|  | 220 | 2 | 
|  | 221 | >>> list.append(a, 'toe')    # same as a.append('toe') | 
|  | 222 | >>> a | 
|  | 223 | ['tic', 'tac', 'toe'] | 
|  | 224 | >>> | 
|  | 225 |  | 
|  | 226 | This is just like it is for user-defined classes. | 
|  | 227 | """ | 
|  | 228 |  | 
|  | 229 | test_4 = """ | 
|  | 230 |  | 
|  | 231 | Static methods and class methods | 
|  | 232 |  | 
|  | 233 | The new introspection API makes it possible to add static methods and class | 
|  | 234 | methods. Static methods are easy to describe: they behave pretty much like | 
|  | 235 | static methods in C++ or Java. Here's an example: | 
|  | 236 |  | 
|  | 237 | >>> class C: | 
| Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 238 | ... | 
| Guido van Rossum | 5a8a037 | 2005-01-16 00:25:31 +0000 | [diff] [blame] | 239 | ...     @staticmethod | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 240 | ...     def foo(x, y): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 241 | ...         print("staticmethod", x, y) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 242 |  | 
|  | 243 | >>> C.foo(1, 2) | 
|  | 244 | staticmethod 1 2 | 
|  | 245 | >>> c = C() | 
|  | 246 | >>> c.foo(1, 2) | 
|  | 247 | staticmethod 1 2 | 
|  | 248 |  | 
|  | 249 | Class methods use a similar pattern to declare methods that receive an | 
|  | 250 | implicit first argument that is the *class* for which they are invoked. | 
|  | 251 |  | 
|  | 252 | >>> class C: | 
| Guido van Rossum | 5a8a037 | 2005-01-16 00:25:31 +0000 | [diff] [blame] | 253 | ...     @classmethod | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 254 | ...     def foo(cls, y): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 255 | ...         print("classmethod", cls, y) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 256 |  | 
|  | 257 | >>> C.foo(1) | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 258 | classmethod <class 'test.test_descrtut.C'> 1 | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 259 | >>> c = C() | 
|  | 260 | >>> c.foo(1) | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 261 | classmethod <class 'test.test_descrtut.C'> 1 | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 262 |  | 
|  | 263 | >>> class D(C): | 
|  | 264 | ...     pass | 
|  | 265 |  | 
|  | 266 | >>> D.foo(1) | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 267 | classmethod <class 'test.test_descrtut.D'> 1 | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 268 | >>> d = D() | 
|  | 269 | >>> d.foo(1) | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 270 | classmethod <class 'test.test_descrtut.D'> 1 | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 271 |  | 
|  | 272 | This prints "classmethod __main__.D 1" both times; in other words, the | 
|  | 273 | class passed as the first argument of foo() is the class involved in the | 
|  | 274 | call, not the class involved in the definition of foo(). | 
|  | 275 |  | 
|  | 276 | But notice this: | 
|  | 277 |  | 
|  | 278 | >>> class E(C): | 
| Guido van Rossum | 5a8a037 | 2005-01-16 00:25:31 +0000 | [diff] [blame] | 279 | ...     @classmethod | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 280 | ...     def foo(cls, y): # override C.foo | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 281 | ...         print("E.foo() called") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 282 | ...         C.foo(y) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 283 |  | 
|  | 284 | >>> E.foo(1) | 
|  | 285 | E.foo() called | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 286 | classmethod <class 'test.test_descrtut.C'> 1 | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 287 | >>> e = E() | 
|  | 288 | >>> e.foo(1) | 
|  | 289 | E.foo() called | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 290 | classmethod <class 'test.test_descrtut.C'> 1 | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 291 |  | 
|  | 292 | In this example, the call to C.foo() from E.foo() will see class C as its | 
|  | 293 | first argument, not class E. This is to be expected, since the call | 
|  | 294 | specifies the class C. But it stresses the difference between these class | 
|  | 295 | methods and methods defined in metaclasses (where an upcall to a metamethod | 
|  | 296 | would pass the target class as an explicit first argument). | 
|  | 297 | """ | 
|  | 298 |  | 
|  | 299 | test_5 = """ | 
|  | 300 |  | 
|  | 301 | Attributes defined by get/set methods | 
|  | 302 |  | 
|  | 303 |  | 
| Guido van Rossum | 8bce4ac | 2001-09-06 21:56:42 +0000 | [diff] [blame] | 304 | >>> class property(object): | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 305 | ... | 
|  | 306 | ...     def __init__(self, get, set=None): | 
|  | 307 | ...         self.__get = get | 
|  | 308 | ...         self.__set = set | 
|  | 309 | ... | 
|  | 310 | ...     def __get__(self, inst, type=None): | 
|  | 311 | ...         return self.__get(inst) | 
|  | 312 | ... | 
|  | 313 | ...     def __set__(self, inst, value): | 
|  | 314 | ...         if self.__set is None: | 
| Collin Winter | 3add4d7 | 2007-08-29 23:37:32 +0000 | [diff] [blame] | 315 | ...             raise AttributeError("this attribute is read-only") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 316 | ...         return self.__set(inst, value) | 
|  | 317 |  | 
|  | 318 | Now let's define a class with an attribute x defined by a pair of methods, | 
|  | 319 | getx() and and setx(): | 
|  | 320 |  | 
|  | 321 | >>> class C(object): | 
|  | 322 | ... | 
|  | 323 | ...     def __init__(self): | 
|  | 324 | ...         self.__x = 0 | 
|  | 325 | ... | 
|  | 326 | ...     def getx(self): | 
|  | 327 | ...         return self.__x | 
|  | 328 | ... | 
|  | 329 | ...     def setx(self, x): | 
|  | 330 | ...         if x < 0: x = 0 | 
|  | 331 | ...         self.__x = x | 
|  | 332 | ... | 
| Guido van Rossum | 8bce4ac | 2001-09-06 21:56:42 +0000 | [diff] [blame] | 333 | ...     x = property(getx, setx) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 334 |  | 
|  | 335 | Here's a small demonstration: | 
|  | 336 |  | 
|  | 337 | >>> a = C() | 
|  | 338 | >>> a.x = 10 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 339 | >>> print(a.x) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 340 | 10 | 
|  | 341 | >>> a.x = -10 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 342 | >>> print(a.x) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 343 | 0 | 
|  | 344 | >>> | 
|  | 345 |  | 
| Guido van Rossum | 8bce4ac | 2001-09-06 21:56:42 +0000 | [diff] [blame] | 346 | Hmm -- property is builtin now, so let's try it that way too. | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 347 |  | 
| Guido van Rossum | 8bce4ac | 2001-09-06 21:56:42 +0000 | [diff] [blame] | 348 | >>> del property  # unmask the builtin | 
|  | 349 | >>> property | 
| Martin v. Löwis | 250ad61 | 2008-04-07 05:43:42 +0000 | [diff] [blame] | 350 | <class 'property'> | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 351 |  | 
|  | 352 | >>> class C(object): | 
|  | 353 | ...     def __init__(self): | 
|  | 354 | ...         self.__x = 0 | 
|  | 355 | ...     def getx(self): | 
|  | 356 | ...         return self.__x | 
|  | 357 | ...     def setx(self, x): | 
|  | 358 | ...         if x < 0: x = 0 | 
|  | 359 | ...         self.__x = x | 
| Guido van Rossum | 8bce4ac | 2001-09-06 21:56:42 +0000 | [diff] [blame] | 360 | ...     x = property(getx, setx) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 361 |  | 
|  | 362 |  | 
|  | 363 | >>> a = C() | 
|  | 364 | >>> a.x = 10 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 365 | >>> print(a.x) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 366 | 10 | 
|  | 367 | >>> a.x = -10 | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 368 | >>> print(a.x) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 369 | 0 | 
|  | 370 | >>> | 
|  | 371 | """ | 
|  | 372 |  | 
|  | 373 | test_6 = """ | 
|  | 374 |  | 
|  | 375 | Method resolution order | 
|  | 376 |  | 
|  | 377 | This example is implicit in the writeup. | 
|  | 378 |  | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 379 | >>> class A:    # implicit new-style class | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 380 | ...     def save(self): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 381 | ...         print("called A.save()") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 382 | >>> class B(A): | 
|  | 383 | ...     pass | 
|  | 384 | >>> class C(A): | 
|  | 385 | ...     def save(self): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 386 | ...         print("called C.save()") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 387 | >>> class D(B, C): | 
|  | 388 | ...     pass | 
|  | 389 |  | 
|  | 390 | >>> D().save() | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 391 | called C.save() | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 392 |  | 
| Thomas Wouters | 28bc768 | 2006-04-15 09:03:16 +0000 | [diff] [blame] | 393 | >>> class A(object):  # explicit new-style class | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 394 | ...     def save(self): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 395 | ...         print("called A.save()") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 396 | >>> class B(A): | 
|  | 397 | ...     pass | 
|  | 398 | >>> class C(A): | 
|  | 399 | ...     def save(self): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 400 | ...         print("called C.save()") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 401 | >>> class D(B, C): | 
|  | 402 | ...     pass | 
|  | 403 |  | 
|  | 404 | >>> D().save() | 
|  | 405 | called C.save() | 
|  | 406 | """ | 
|  | 407 |  | 
|  | 408 | class A(object): | 
|  | 409 | def m(self): | 
|  | 410 | return "A" | 
|  | 411 |  | 
|  | 412 | class B(A): | 
|  | 413 | def m(self): | 
|  | 414 | return "B" + super(B, self).m() | 
|  | 415 |  | 
|  | 416 | class C(A): | 
|  | 417 | def m(self): | 
|  | 418 | return "C" + super(C, self).m() | 
|  | 419 |  | 
|  | 420 | class D(C, B): | 
|  | 421 | def m(self): | 
|  | 422 | return "D" + super(D, self).m() | 
|  | 423 |  | 
|  | 424 |  | 
|  | 425 | test_7 = """ | 
|  | 426 |  | 
|  | 427 | Cooperative methods and "super" | 
|  | 428 |  | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 429 | >>> print(D().m()) # "DCBA" | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 430 | DCBA | 
|  | 431 | """ | 
|  | 432 |  | 
|  | 433 | test_8 = """ | 
|  | 434 |  | 
|  | 435 | Backwards incompatibilities | 
|  | 436 |  | 
|  | 437 | >>> class A: | 
|  | 438 | ...     def foo(self): | 
| Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 439 | ...         print("called A.foo()") | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 440 |  | 
|  | 441 | >>> class B(A): | 
|  | 442 | ...     pass | 
|  | 443 |  | 
|  | 444 | >>> class C(A): | 
|  | 445 | ...     def foo(self): | 
|  | 446 | ...         B.foo(self) | 
|  | 447 |  | 
|  | 448 | >>> C().foo() | 
| Christian Heimes | 4a22b5d | 2007-11-25 09:39:14 +0000 | [diff] [blame] | 449 | called A.foo() | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 450 |  | 
|  | 451 | >>> class C(A): | 
|  | 452 | ...     def foo(self): | 
|  | 453 | ...         A.foo(self) | 
|  | 454 | >>> C().foo() | 
|  | 455 | called A.foo() | 
|  | 456 | """ | 
|  | 457 |  | 
|  | 458 | __test__ = {"tut1": test_1, | 
|  | 459 | "tut2": test_2, | 
|  | 460 | "tut3": test_3, | 
|  | 461 | "tut4": test_4, | 
|  | 462 | "tut5": test_5, | 
|  | 463 | "tut6": test_6, | 
|  | 464 | "tut7": test_7, | 
|  | 465 | "tut8": test_8} | 
|  | 466 |  | 
|  | 467 | # Magic test name that regrtest.py invokes *after* importing this module. | 
|  | 468 | # This worms around a bootstrap problem. | 
|  | 469 | # Note that doctest and regrtest both look in sys.argv for a "-v" argument, | 
|  | 470 | # so this works as expected in both ways of running regrtest. | 
| Tim Peters | a0a6222 | 2001-09-09 06:12:01 +0000 | [diff] [blame] | 471 | def test_main(verbose=None): | 
|  | 472 | # Obscure:  import this module as test.test_descrtut instead of as | 
|  | 473 | # plain test_descrtut because the name of this module works its way | 
|  | 474 | # into the doctest examples, and unless the full test.test_descrtut | 
|  | 475 | # business is used the name can change depending on how the test is | 
|  | 476 | # invoked. | 
| Benjamin Peterson | ee8712c | 2008-05-20 21:35:26 +0000 | [diff] [blame] | 477 | from test import support, test_descrtut | 
|  | 478 | support.run_doctest(test_descrtut, verbose) | 
| Tim Peters | 95c99e5 | 2001-09-03 01:24:30 +0000 | [diff] [blame] | 479 |  | 
|  | 480 | # This part isn't needed for regrtest, but for running the test directly. | 
|  | 481 | if __name__ == "__main__": | 
| Tim Peters | a0a6222 | 2001-09-09 06:12:01 +0000 | [diff] [blame] | 482 | test_main(1) |