| # 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. | 
 |  | 
 | from test.test_support import sortdict | 
 | import pprint | 
 |  | 
 | class defaultdict(dict): | 
 |     def __init__(self, default=None): | 
 |         dict.__init__(self) | 
 |         self.default = default | 
 |  | 
 |     def __getitem__(self, key): | 
 |         try: | 
 |             return dict.__getitem__(self, key) | 
 |         except KeyError: | 
 |             return self.default | 
 |  | 
 |     def get(self, key, *args): | 
 |         if not args: | 
 |             args = (self.default,) | 
 |         return dict.get(self, key, *args) | 
 |  | 
 |     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 | 
 |     <class 'test.test_descrtut.defaultdict'> | 
 |     >>> 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 | 
 |     <class 'test.test_descrtut.defaultdict'> | 
 |     >>> print a.__class__               # show its class | 
 |     <class 'test.test_descrtut.defaultdict'> | 
 |     >>> print type(a) is a.__class__    # its type is its class | 
 |     True | 
 |     >>> 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 | 
 |     >>> print a[0]                      # a non-existant item | 
 |     0.0 | 
 |     >>> a.merge({1:100, 2:200})         # use a dict method | 
 |     >>> 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): | 
 |     ...     seq.sort() | 
 |     ...     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 | 
 |     >>> 'default' in dir(a) | 
 |     True | 
 |     >>> a.x1 = 100 | 
 |     >>> a.x2 = 200 | 
 |     >>> print a.x1 | 
 |     100 | 
 |     >>> d = dir(a) | 
 |     >>> 'default' in d and 'x1' in d and 'x2' in d | 
 |     True | 
 |     >>> print sortdict(a.__dict__) | 
 |     {'default': -1000, 'x1': 100, 'x2': 200} | 
 |     >>> | 
 | """ | 
 |  | 
 | class defaultdict2(dict): | 
 |     __slots__ = ['default'] | 
 |  | 
 |     def __init__(self, default=None): | 
 |         dict.__init__(self) | 
 |         self.default = default | 
 |  | 
 |     def __getitem__(self, key): | 
 |         try: | 
 |             return dict.__getitem__(self, key) | 
 |         except KeyError: | 
 |             return self.default | 
 |  | 
 |     def get(self, key, *args): | 
 |         if not args: | 
 |             args = (self.default,) | 
 |         return dict.get(self, key, *args) | 
 |  | 
 |     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) | 
 |     True | 
 |     >>> isinstance([], dict) | 
 |     False | 
 |     >>> isinstance([], object) | 
 |     True | 
 |     >>> | 
 |  | 
 | 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__', | 
 |      '__delslice__', | 
 |      '__doc__', | 
 |      '__eq__', | 
 |      '__format__', | 
 |      '__ge__', | 
 |      '__getattribute__', | 
 |      '__getitem__', | 
 |      '__getslice__', | 
 |      '__gt__', | 
 |      '__hash__', | 
 |      '__iadd__', | 
 |      '__imul__', | 
 |      '__init__', | 
 |      '__iter__', | 
 |      '__le__', | 
 |      '__len__', | 
 |      '__lt__', | 
 |      '__mul__', | 
 |      '__ne__', | 
 |      '__new__', | 
 |      '__reduce__', | 
 |      '__reduce_ex__', | 
 |      '__repr__', | 
 |      '__reversed__', | 
 |      '__rmul__', | 
 |      '__setattr__', | 
 |      '__setitem__', | 
 |      '__setslice__', | 
 |      '__sizeof__', | 
 |      '__str__', | 
 |      '__subclasshook__', | 
 |      'append', | 
 |      'count', | 
 |      'extend', | 
 |      'index', | 
 |      'insert', | 
 |      'pop', | 
 |      'remove', | 
 |      'reverse', | 
 |      'sort'] | 
 |  | 
 | 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: | 
 |     ... | 
 |     ...     @staticmethod | 
 |     ...     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: | 
 |     ...     @classmethod | 
 |     ...     def foo(cls, y): | 
 |     ...         print "classmethod", cls, y | 
 |  | 
 |     >>> C.foo(1) | 
 |     classmethod test.test_descrtut.C 1 | 
 |     >>> c = C() | 
 |     >>> c.foo(1) | 
 |     classmethod test.test_descrtut.C 1 | 
 |  | 
 |     >>> class D(C): | 
 |     ...     pass | 
 |  | 
 |     >>> D.foo(1) | 
 |     classmethod test.test_descrtut.D 1 | 
 |     >>> d = D() | 
 |     >>> d.foo(1) | 
 |     classmethod test.test_descrtut.D 1 | 
 |  | 
 | 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): | 
 |     ...     @classmethod | 
 |     ...     def foo(cls, y): # override C.foo | 
 |     ...         print "E.foo() called" | 
 |     ...         C.foo(y) | 
 |  | 
 |     >>> E.foo(1) | 
 |     E.foo() called | 
 |     classmethod test.test_descrtut.C 1 | 
 |     >>> e = E() | 
 |     >>> e.foo(1) | 
 |     E.foo() called | 
 |     classmethod test.test_descrtut.C 1 | 
 |  | 
 | 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 | 
 |  | 
 |  | 
 |     >>> class property(object): | 
 |     ... | 
 |     ...     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 | 
 |     ... | 
 |     ...     x = property(getx, setx) | 
 |  | 
 | Here's a small demonstration: | 
 |  | 
 |     >>> a = C() | 
 |     >>> a.x = 10 | 
 |     >>> print a.x | 
 |     10 | 
 |     >>> a.x = -10 | 
 |     >>> print a.x | 
 |     0 | 
 |     >>> | 
 |  | 
 | Hmm -- property is builtin now, so let's try it that way too. | 
 |  | 
 |     >>> del property  # unmask the builtin | 
 |     >>> property | 
 |     <type 'property'> | 
 |  | 
 |     >>> 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 | 
 |     ...     x = property(getx, setx) | 
 |  | 
 |  | 
 |     >>> 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. | 
 | 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. | 
 |     from test import test_support, test_descrtut | 
 |     test_support.run_doctest(test_descrtut, verbose) | 
 |  | 
 | # This part isn't needed for regrtest, but for running the test directly. | 
 | if __name__ == "__main__": | 
 |     test_main(1) |