| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | # This contains most of the executable examples from Guido's descr | 
					
						
							|  |  |  | # tutorial, once at | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #     http://www.python.org/2.2/descrintro.html | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # A few examples left implicit in the writeup were fleshed out, a few were | 
					
						
							|  |  |  | # skipped due to lack of interest (e.g., faking super() by hand isn't | 
					
						
							|  |  |  | # of much interest anymore), and a few were fiddled to make the output | 
					
						
							|  |  |  | # deterministic. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-23 19:04:11 +00:00
										 |  |  | from test.test_support import sortdict | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | import pprint | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  | class defaultdict(dict): | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     def __init__(self, default=None): | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |         dict.__init__(self) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |         self.default = default | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, key): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |             return dict.__getitem__(self, key) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |         except KeyError: | 
					
						
							|  |  |  |             return self.default | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get(self, key, *args): | 
					
						
							|  |  |  |         if not args: | 
					
						
							|  |  |  |             args = (self.default,) | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |         return dict.get(self, key, *args) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def merge(self, other): | 
					
						
							|  |  |  |         for key in other: | 
					
						
							|  |  |  |             if key not in self: | 
					
						
							|  |  |  |                 self[key] = other[key] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_1 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Here's the new type at work: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> print defaultdict               # show our type | 
					
						
							| 
									
										
										
										
											2001-09-25 03:56:29 +00:00
										 |  |  |     <class 'test.test_descrtut.defaultdict'> | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> print type(defaultdict)         # its metatype | 
					
						
							|  |  |  |     <type 'type'> | 
					
						
							|  |  |  |     >>> a = defaultdict(default=0.0)    # create an instance | 
					
						
							|  |  |  |     >>> print a                         # show the instance | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  |     >>> print type(a)                   # show its type | 
					
						
							| 
									
										
										
										
											2001-09-25 03:56:29 +00:00
										 |  |  |     <class 'test.test_descrtut.defaultdict'> | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> print a.__class__               # show its class | 
					
						
							| 
									
										
										
										
											2001-09-25 03:56:29 +00:00
										 |  |  |     <class 'test.test_descrtut.defaultdict'> | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> print type(a) is a.__class__    # its type is its class | 
					
						
							| 
									
										
										
										
											2002-04-03 22:41:51 +00:00
										 |  |  |     True | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> a[1] = 3.25                     # modify the instance | 
					
						
							|  |  |  |     >>> print a                         # show the new value | 
					
						
							|  |  |  |     {1: 3.25} | 
					
						
							|  |  |  |     >>> print a[1]                      # show the new item | 
					
						
							|  |  |  |     3.25 | 
					
						
							| 
									
										
										
										
											2009-02-21 20:27:01 +00:00
										 |  |  |     >>> print a[0]                      # a non-existent item | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     0.0 | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |     >>> a.merge({1:100, 2:200})         # use a dict method | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> print sortdict(a)               # show the result | 
					
						
							|  |  |  |     {1: 3.25, 2: 200} | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | We can also use the new type in contexts where classic only allows "real" | 
					
						
							|  |  |  | dictionaries, such as the locals/globals dictionaries for the exec | 
					
						
							|  |  |  | statement or the built-in function eval(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> def sorted(seq): | 
					
						
							| 
									
										
										
										
											2010-02-03 05:37:26 +00:00
										 |  |  |     ...     seq.sort(key=str) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     ...     return seq | 
					
						
							|  |  |  |     >>> print sorted(a.keys()) | 
					
						
							|  |  |  |     [1, 2] | 
					
						
							|  |  |  |     >>> exec "x = 3; print x" in a | 
					
						
							|  |  |  |     3 | 
					
						
							|  |  |  |     >>> print sorted(a.keys()) | 
					
						
							|  |  |  |     [1, 2, '__builtins__', 'x'] | 
					
						
							|  |  |  |     >>> print a['x'] | 
					
						
							|  |  |  |     3 | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now I'll show that defaultdict instances have dynamic instance variables, | 
					
						
							|  |  |  | just like classic classes: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> a.default = -1 | 
					
						
							|  |  |  |     >>> print a["noway"] | 
					
						
							|  |  |  |     -1 | 
					
						
							|  |  |  |     >>> a.default = -1000 | 
					
						
							|  |  |  |     >>> print a["noway"] | 
					
						
							|  |  |  |     -1000 | 
					
						
							| 
									
										
										
										
											2001-09-03 05:47:38 +00:00
										 |  |  |     >>> 'default' in dir(a) | 
					
						
							| 
									
										
										
										
											2002-04-03 22:41:51 +00:00
										 |  |  |     True | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> a.x1 = 100 | 
					
						
							|  |  |  |     >>> a.x2 = 200 | 
					
						
							|  |  |  |     >>> print a.x1 | 
					
						
							|  |  |  |     100 | 
					
						
							| 
									
										
										
										
											2001-09-03 05:47:38 +00:00
										 |  |  |     >>> d = dir(a) | 
					
						
							|  |  |  |     >>> 'default' in d and 'x1' in d and 'x2' in d | 
					
						
							| 
									
										
										
										
											2002-04-03 22:41:51 +00:00
										 |  |  |     True | 
					
						
							| 
									
										
										
										
											2003-02-18 16:54:41 +00:00
										 |  |  |     >>> print sortdict(a.__dict__) | 
					
						
							|  |  |  |     {'default': -1000, 'x1': 100, 'x2': 200} | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  | class defaultdict2(dict): | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     __slots__ = ['default'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, default=None): | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |         dict.__init__(self) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |         self.default = default | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, key): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |             return dict.__getitem__(self, key) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |         except KeyError: | 
					
						
							|  |  |  |             return self.default | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get(self, key, *args): | 
					
						
							|  |  |  |         if not args: | 
					
						
							|  |  |  |             args = (self.default,) | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |         return dict.get(self, key, *args) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def merge(self, other): | 
					
						
							|  |  |  |         for key in other: | 
					
						
							|  |  |  |             if key not in self: | 
					
						
							|  |  |  |                 self[key] = other[key] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_2 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The __slots__ declaration takes a list of instance variables, and reserves | 
					
						
							|  |  |  | space for exactly these in the instance. When __slots__ is used, other | 
					
						
							|  |  |  | instance variables cannot be assigned to: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> a = defaultdict2(default=0.0) | 
					
						
							|  |  |  |     >>> a[1] | 
					
						
							|  |  |  |     0.0 | 
					
						
							|  |  |  |     >>> a.default = -1 | 
					
						
							|  |  |  |     >>> a[1] | 
					
						
							|  |  |  |     -1 | 
					
						
							|  |  |  |     >>> a.x1 = 1 | 
					
						
							|  |  |  |     Traceback (most recent call last): | 
					
						
							|  |  |  |       File "<stdin>", line 1, in ? | 
					
						
							|  |  |  |     AttributeError: 'defaultdict2' object has no attribute 'x1' | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_3 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Introspecting instances of built-in types | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For instance of built-in types, x.__class__ is now the same as type(x): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> type([]) | 
					
						
							|  |  |  |     <type 'list'> | 
					
						
							|  |  |  |     >>> [].__class__ | 
					
						
							|  |  |  |     <type 'list'> | 
					
						
							|  |  |  |     >>> list | 
					
						
							|  |  |  |     <type 'list'> | 
					
						
							|  |  |  |     >>> isinstance([], list) | 
					
						
							| 
									
										
										
										
											2002-04-03 22:41:51 +00:00
										 |  |  |     True | 
					
						
							| 
									
										
										
										
											2001-10-29 22:25:45 +00:00
										 |  |  |     >>> isinstance([], dict) | 
					
						
							| 
									
										
										
										
											2002-04-03 22:41:51 +00:00
										 |  |  |     False | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> isinstance([], object) | 
					
						
							| 
									
										
										
										
											2002-04-03 22:41:51 +00:00
										 |  |  |     True | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Under the new proposal, the __methods__ attribute no longer exists: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> [].__methods__ | 
					
						
							|  |  |  |     Traceback (most recent call last): | 
					
						
							|  |  |  |       File "<stdin>", line 1, in ? | 
					
						
							|  |  |  |     AttributeError: 'list' object has no attribute '__methods__' | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Instead, you can get the same information from the list type: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> pprint.pprint(dir(list))    # like list.__dict__.keys(), but sorted | 
					
						
							|  |  |  |     ['__add__', | 
					
						
							|  |  |  |      '__class__', | 
					
						
							|  |  |  |      '__contains__', | 
					
						
							|  |  |  |      '__delattr__', | 
					
						
							|  |  |  |      '__delitem__', | 
					
						
							| 
									
										
										
										
											2001-10-09 19:39:46 +00:00
										 |  |  |      '__delslice__', | 
					
						
							| 
									
										
										
										
											2002-02-19 04:25:19 +00:00
										 |  |  |      '__doc__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__eq__', | 
					
						
							| 
									
										
										
											
												Backport of PEP 3101, Advanced String Formatting, from py3k.
Highlights:
 - Adding PyObject_Format.
 - Adding string.Format class.
 - Adding __format__ for str, unicode, int, long, float, datetime.
 - Adding builtin format.
 - Adding ''.format and u''.format.
 - str/unicode fixups for formatters.
The files in Objects/stringlib that implement PEP 3101 (stringdefs.h,
unicodedefs.h, formatter.h, string_format.h) are identical in trunk
and py3k.  Any changes from here on should be made to trunk, and
changes will propogate to py3k).
											
										 
											2008-02-17 19:46:49 +00:00
										 |  |  |      '__format__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__ge__', | 
					
						
							| 
									
										
										
										
											2001-09-21 19:29:08 +00:00
										 |  |  |      '__getattribute__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__getitem__', | 
					
						
							|  |  |  |      '__getslice__', | 
					
						
							|  |  |  |      '__gt__', | 
					
						
							|  |  |  |      '__hash__', | 
					
						
							|  |  |  |      '__iadd__', | 
					
						
							|  |  |  |      '__imul__', | 
					
						
							|  |  |  |      '__init__', | 
					
						
							| 
									
										
										
										
											2002-05-31 21:40:38 +00:00
										 |  |  |      '__iter__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__le__', | 
					
						
							|  |  |  |      '__len__', | 
					
						
							|  |  |  |      '__lt__', | 
					
						
							|  |  |  |      '__mul__', | 
					
						
							|  |  |  |      '__ne__', | 
					
						
							|  |  |  |      '__new__', | 
					
						
							| 
									
										
										
										
											2001-09-25 16:25:58 +00:00
										 |  |  |      '__reduce__', | 
					
						
							| 
									
										
										
										
											2003-02-18 22:05:12 +00:00
										 |  |  |      '__reduce_ex__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__repr__', | 
					
						
							| 
									
										
										
										
											2003-11-08 12:39:53 +00:00
										 |  |  |      '__reversed__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__rmul__', | 
					
						
							|  |  |  |      '__setattr__', | 
					
						
							|  |  |  |      '__setitem__', | 
					
						
							|  |  |  |      '__setslice__', | 
					
						
							| 
									
										
										
										
											2008-06-01 17:05:56 +00:00
										 |  |  |      '__sizeof__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      '__str__', | 
					
						
							| 
									
										
										
										
											2008-02-28 04:45:36 +00:00
										 |  |  |      '__subclasshook__', | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |      'append', | 
					
						
							|  |  |  |      'count', | 
					
						
							|  |  |  |      'extend', | 
					
						
							|  |  |  |      'index', | 
					
						
							|  |  |  |      'insert', | 
					
						
							|  |  |  |      'pop', | 
					
						
							|  |  |  |      'remove', | 
					
						
							|  |  |  |      'reverse', | 
					
						
							| 
									
										
										
										
											2003-12-17 20:43:33 +00:00
										 |  |  |      'sort'] | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The new introspection API gives more information than the old one:  in | 
					
						
							|  |  |  | addition to the regular methods, it also shows the methods that are | 
					
						
							|  |  |  | normally invoked through special notations, e.g. __iadd__ (+=), __len__ | 
					
						
							|  |  |  | (len), __ne__ (!=). You can invoke any method from this list directly: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> a = ['tic', 'tac'] | 
					
						
							|  |  |  |     >>> list.__len__(a)          # same as len(a) | 
					
						
							|  |  |  |     2 | 
					
						
							|  |  |  |     >>> a.__len__()              # ditto | 
					
						
							|  |  |  |     2 | 
					
						
							|  |  |  |     >>> list.append(a, 'toe')    # same as a.append('toe') | 
					
						
							|  |  |  |     >>> a | 
					
						
							|  |  |  |     ['tic', 'tac', 'toe'] | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is just like it is for user-defined classes. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_4 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Static methods and class methods | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The new introspection API makes it possible to add static methods and class | 
					
						
							|  |  |  | methods. Static methods are easy to describe: they behave pretty much like | 
					
						
							|  |  |  | static methods in C++ or Java. Here's an example: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> class C: | 
					
						
							|  |  |  |     ... | 
					
						
							| 
									
										
										
										
											2005-01-16 00:25:31 +00:00
										 |  |  |     ...     @staticmethod | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     ...     def foo(x, y): | 
					
						
							|  |  |  |     ...         print "staticmethod", x, y | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> C.foo(1, 2) | 
					
						
							|  |  |  |     staticmethod 1 2 | 
					
						
							|  |  |  |     >>> c = C() | 
					
						
							|  |  |  |     >>> c.foo(1, 2) | 
					
						
							|  |  |  |     staticmethod 1 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Class methods use a similar pattern to declare methods that receive an | 
					
						
							|  |  |  | implicit first argument that is the *class* for which they are invoked. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> class C: | 
					
						
							| 
									
										
										
										
											2005-01-16 00:25:31 +00:00
										 |  |  |     ...     @classmethod | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     ...     def foo(cls, y): | 
					
						
							|  |  |  |     ...         print "classmethod", cls, y | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> C.foo(1) | 
					
						
							| 
									
										
										
										
											2001-09-09 01:21:31 +00:00
										 |  |  |     classmethod test.test_descrtut.C 1 | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> c = C() | 
					
						
							|  |  |  |     >>> c.foo(1) | 
					
						
							| 
									
										
										
										
											2001-09-09 01:21:31 +00:00
										 |  |  |     classmethod test.test_descrtut.C 1 | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     >>> class D(C): | 
					
						
							|  |  |  |     ...     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> D.foo(1) | 
					
						
							| 
									
										
										
										
											2001-09-09 01:21:31 +00:00
										 |  |  |     classmethod test.test_descrtut.D 1 | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> d = D() | 
					
						
							|  |  |  |     >>> d.foo(1) | 
					
						
							| 
									
										
										
										
											2001-09-09 01:21:31 +00:00
										 |  |  |     classmethod test.test_descrtut.D 1 | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This prints "classmethod __main__.D 1" both times; in other words, the | 
					
						
							|  |  |  | class passed as the first argument of foo() is the class involved in the | 
					
						
							|  |  |  | call, not the class involved in the definition of foo(). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | But notice this: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> class E(C): | 
					
						
							| 
									
										
										
										
											2005-01-16 00:25:31 +00:00
										 |  |  |     ...     @classmethod | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     ...     def foo(cls, y): # override C.foo | 
					
						
							|  |  |  |     ...         print "E.foo() called" | 
					
						
							|  |  |  |     ...         C.foo(y) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> E.foo(1) | 
					
						
							|  |  |  |     E.foo() called | 
					
						
							| 
									
										
										
										
											2001-09-09 01:21:31 +00:00
										 |  |  |     classmethod test.test_descrtut.C 1 | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     >>> e = E() | 
					
						
							|  |  |  |     >>> e.foo(1) | 
					
						
							|  |  |  |     E.foo() called | 
					
						
							| 
									
										
										
										
											2001-09-09 01:21:31 +00:00
										 |  |  |     classmethod test.test_descrtut.C 1 | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | In this example, the call to C.foo() from E.foo() will see class C as its | 
					
						
							|  |  |  | first argument, not class E. This is to be expected, since the call | 
					
						
							|  |  |  | specifies the class C. But it stresses the difference between these class | 
					
						
							|  |  |  | methods and methods defined in metaclasses (where an upcall to a metamethod | 
					
						
							|  |  |  | would pass the target class as an explicit first argument). | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_5 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Attributes defined by get/set methods | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-06 21:56:42 +00:00
										 |  |  |     >>> class property(object): | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  |     ... | 
					
						
							|  |  |  |     ...     def __init__(self, get, set=None): | 
					
						
							|  |  |  |     ...         self.__get = get | 
					
						
							|  |  |  |     ...         self.__set = set | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  |     ...     def __get__(self, inst, type=None): | 
					
						
							|  |  |  |     ...         return self.__get(inst) | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  |     ...     def __set__(self, inst, value): | 
					
						
							|  |  |  |     ...         if self.__set is None: | 
					
						
							|  |  |  |     ...             raise AttributeError, "this attribute is read-only" | 
					
						
							|  |  |  |     ...         return self.__set(inst, value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now let's define a class with an attribute x defined by a pair of methods, | 
					
						
							|  |  |  | getx() and and setx(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> class C(object): | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  |     ...     def __init__(self): | 
					
						
							|  |  |  |     ...         self.__x = 0 | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  |     ...     def getx(self): | 
					
						
							|  |  |  |     ...         return self.__x | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  |     ...     def setx(self, x): | 
					
						
							|  |  |  |     ...         if x < 0: x = 0 | 
					
						
							|  |  |  |     ...         self.__x = x | 
					
						
							|  |  |  |     ... | 
					
						
							| 
									
										
										
										
											2001-09-06 21:56:42 +00:00
										 |  |  |     ...     x = property(getx, setx) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Here's a small demonstration: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> a = C() | 
					
						
							|  |  |  |     >>> a.x = 10 | 
					
						
							|  |  |  |     >>> print a.x | 
					
						
							|  |  |  |     10 | 
					
						
							|  |  |  |     >>> a.x = -10 | 
					
						
							|  |  |  |     >>> print a.x | 
					
						
							|  |  |  |     0 | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-06 21:56:42 +00:00
										 |  |  | Hmm -- property is builtin now, so let's try it that way too. | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-06 21:56:42 +00:00
										 |  |  |     >>> del property  # unmask the builtin | 
					
						
							|  |  |  |     >>> property | 
					
						
							|  |  |  |     <type 'property'> | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     >>> class C(object): | 
					
						
							|  |  |  |     ...     def __init__(self): | 
					
						
							|  |  |  |     ...         self.__x = 0 | 
					
						
							|  |  |  |     ...     def getx(self): | 
					
						
							|  |  |  |     ...         return self.__x | 
					
						
							|  |  |  |     ...     def setx(self, x): | 
					
						
							|  |  |  |     ...         if x < 0: x = 0 | 
					
						
							|  |  |  |     ...         self.__x = x | 
					
						
							| 
									
										
										
										
											2001-09-06 21:56:42 +00:00
										 |  |  |     ...     x = property(getx, setx) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     >>> a = C() | 
					
						
							|  |  |  |     >>> a.x = 10 | 
					
						
							|  |  |  |     >>> print a.x | 
					
						
							|  |  |  |     10 | 
					
						
							|  |  |  |     >>> a.x = -10 | 
					
						
							|  |  |  |     >>> print a.x | 
					
						
							|  |  |  |     0 | 
					
						
							|  |  |  |     >>> | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_6 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Method resolution order | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This example is implicit in the writeup. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> class A:    # classic class | 
					
						
							|  |  |  | ...     def save(self): | 
					
						
							|  |  |  | ...         print "called A.save()" | 
					
						
							|  |  |  | >>> class B(A): | 
					
						
							|  |  |  | ...     pass | 
					
						
							|  |  |  | >>> class C(A): | 
					
						
							|  |  |  | ...     def save(self): | 
					
						
							|  |  |  | ...         print "called C.save()" | 
					
						
							|  |  |  | >>> class D(B, C): | 
					
						
							|  |  |  | ...     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> D().save() | 
					
						
							|  |  |  | called A.save() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> class A(object):  # new class | 
					
						
							|  |  |  | ...     def save(self): | 
					
						
							|  |  |  | ...         print "called A.save()" | 
					
						
							|  |  |  | >>> class B(A): | 
					
						
							|  |  |  | ...     pass | 
					
						
							|  |  |  | >>> class C(A): | 
					
						
							|  |  |  | ...     def save(self): | 
					
						
							|  |  |  | ...         print "called C.save()" | 
					
						
							|  |  |  | >>> class D(B, C): | 
					
						
							|  |  |  | ...     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> D().save() | 
					
						
							|  |  |  | called C.save() | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class A(object): | 
					
						
							|  |  |  |     def m(self): | 
					
						
							|  |  |  |         return "A" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class B(A): | 
					
						
							|  |  |  |     def m(self): | 
					
						
							|  |  |  |         return "B" + super(B, self).m() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class C(A): | 
					
						
							|  |  |  |     def m(self): | 
					
						
							|  |  |  |         return "C" + super(C, self).m() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class D(C, B): | 
					
						
							|  |  |  |     def m(self): | 
					
						
							|  |  |  |         return "D" + super(D, self).m() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_7 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Cooperative methods and "super" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> print D().m() # "DCBA" | 
					
						
							|  |  |  | DCBA | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test_8 = """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Backwards incompatibilities | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> class A: | 
					
						
							|  |  |  | ...     def foo(self): | 
					
						
							|  |  |  | ...         print "called A.foo()" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> class B(A): | 
					
						
							|  |  |  | ...     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> class C(A): | 
					
						
							|  |  |  | ...     def foo(self): | 
					
						
							|  |  |  | ...         B.foo(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> C().foo() | 
					
						
							|  |  |  | Traceback (most recent call last): | 
					
						
							|  |  |  |  ... | 
					
						
							|  |  |  | TypeError: unbound method foo() must be called with B instance as first argument (got C instance instead) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | >>> class C(A): | 
					
						
							|  |  |  | ...     def foo(self): | 
					
						
							|  |  |  | ...         A.foo(self) | 
					
						
							|  |  |  | >>> C().foo() | 
					
						
							|  |  |  | called A.foo() | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __test__ = {"tut1": test_1, | 
					
						
							|  |  |  |             "tut2": test_2, | 
					
						
							|  |  |  |             "tut3": test_3, | 
					
						
							|  |  |  |             "tut4": test_4, | 
					
						
							|  |  |  |             "tut5": test_5, | 
					
						
							|  |  |  |             "tut6": test_6, | 
					
						
							|  |  |  |             "tut7": test_7, | 
					
						
							|  |  |  |             "tut8": test_8} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Magic test name that regrtest.py invokes *after* importing this module. | 
					
						
							|  |  |  | # This worms around a bootstrap problem. | 
					
						
							|  |  |  | # Note that doctest and regrtest both look in sys.argv for a "-v" argument, | 
					
						
							|  |  |  | # so this works as expected in both ways of running regrtest. | 
					
						
							| 
									
										
										
										
											2001-09-09 06:12:01 +00:00
										 |  |  | def test_main(verbose=None): | 
					
						
							|  |  |  |     # Obscure:  import this module as test.test_descrtut instead of as | 
					
						
							|  |  |  |     # plain test_descrtut because the name of this module works its way | 
					
						
							|  |  |  |     # into the doctest examples, and unless the full test.test_descrtut | 
					
						
							|  |  |  |     # business is used the name can change depending on how the test is | 
					
						
							|  |  |  |     # invoked. | 
					
						
							| 
									
										
										
										
											2002-07-23 19:04:11 +00:00
										 |  |  |     from test import test_support, test_descrtut | 
					
						
							|  |  |  |     test_support.run_doctest(test_descrtut, verbose) | 
					
						
							| 
									
										
										
										
											2001-09-03 01:24:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # This part isn't needed for regrtest, but for running the test directly. | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2001-09-09 06:12:01 +00:00
										 |  |  |     test_main(1) |