17db96d56Sopenharmony_ci# This contains most of the executable examples from Guido's descr
27db96d56Sopenharmony_ci# tutorial, once at
37db96d56Sopenharmony_ci#
47db96d56Sopenharmony_ci#     https://www.python.org/download/releases/2.2.3/descrintro/
57db96d56Sopenharmony_ci#
67db96d56Sopenharmony_ci# A few examples left implicit in the writeup were fleshed out, a few were
77db96d56Sopenharmony_ci# skipped due to lack of interest (e.g., faking super() by hand isn't
87db96d56Sopenharmony_ci# of much interest anymore), and a few were fiddled to make the output
97db96d56Sopenharmony_ci# deterministic.
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_cifrom test.support import sortdict
127db96d56Sopenharmony_ciimport pprint
137db96d56Sopenharmony_ciimport doctest
147db96d56Sopenharmony_ciimport unittest
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciclass defaultdict(dict):
187db96d56Sopenharmony_ci    def __init__(self, default=None):
197db96d56Sopenharmony_ci        dict.__init__(self)
207db96d56Sopenharmony_ci        self.default = default
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci    def __getitem__(self, key):
237db96d56Sopenharmony_ci        try:
247db96d56Sopenharmony_ci            return dict.__getitem__(self, key)
257db96d56Sopenharmony_ci        except KeyError:
267db96d56Sopenharmony_ci            return self.default
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci    def get(self, key, *args):
297db96d56Sopenharmony_ci        if not args:
307db96d56Sopenharmony_ci            args = (self.default,)
317db96d56Sopenharmony_ci        return dict.get(self, key, *args)
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci    def merge(self, other):
347db96d56Sopenharmony_ci        for key in other:
357db96d56Sopenharmony_ci            if key not in self:
367db96d56Sopenharmony_ci                self[key] = other[key]
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_citest_1 = """
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ciHere's the new type at work:
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci    >>> print(defaultdict)              # show our type
437db96d56Sopenharmony_ci    <class 'test.test_descrtut.defaultdict'>
447db96d56Sopenharmony_ci    >>> print(type(defaultdict))        # its metatype
457db96d56Sopenharmony_ci    <class 'type'>
467db96d56Sopenharmony_ci    >>> a = defaultdict(default=0.0)    # create an instance
477db96d56Sopenharmony_ci    >>> print(a)                        # show the instance
487db96d56Sopenharmony_ci    {}
497db96d56Sopenharmony_ci    >>> print(type(a))                  # show its type
507db96d56Sopenharmony_ci    <class 'test.test_descrtut.defaultdict'>
517db96d56Sopenharmony_ci    >>> print(a.__class__)              # show its class
527db96d56Sopenharmony_ci    <class 'test.test_descrtut.defaultdict'>
537db96d56Sopenharmony_ci    >>> print(type(a) is a.__class__)   # its type is its class
547db96d56Sopenharmony_ci    True
557db96d56Sopenharmony_ci    >>> a[1] = 3.25                     # modify the instance
567db96d56Sopenharmony_ci    >>> print(a)                        # show the new value
577db96d56Sopenharmony_ci    {1: 3.25}
587db96d56Sopenharmony_ci    >>> print(a[1])                     # show the new item
597db96d56Sopenharmony_ci    3.25
607db96d56Sopenharmony_ci    >>> print(a[0])                     # a non-existent item
617db96d56Sopenharmony_ci    0.0
627db96d56Sopenharmony_ci    >>> a.merge({1:100, 2:200})         # use a dict method
637db96d56Sopenharmony_ci    >>> print(sortdict(a))              # show the result
647db96d56Sopenharmony_ci    {1: 3.25, 2: 200}
657db96d56Sopenharmony_ci    >>>
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ciWe can also use the new type in contexts where classic only allows "real"
687db96d56Sopenharmony_cidictionaries, such as the locals/globals dictionaries for the exec
697db96d56Sopenharmony_cistatement or the built-in function eval():
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci    >>> print(sorted(a.keys()))
727db96d56Sopenharmony_ci    [1, 2]
737db96d56Sopenharmony_ci    >>> a['print'] = print              # need the print function here
747db96d56Sopenharmony_ci    >>> exec("x = 3; print(x)", a)
757db96d56Sopenharmony_ci    3
767db96d56Sopenharmony_ci    >>> print(sorted(a.keys(), key=lambda x: (str(type(x)), x)))
777db96d56Sopenharmony_ci    [1, 2, '__builtins__', 'print', 'x']
787db96d56Sopenharmony_ci    >>> print(a['x'])
797db96d56Sopenharmony_ci    3
807db96d56Sopenharmony_ci    >>>
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ciNow I'll show that defaultdict instances have dynamic instance variables,
837db96d56Sopenharmony_cijust like classic classes:
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci    >>> a.default = -1
867db96d56Sopenharmony_ci    >>> print(a["noway"])
877db96d56Sopenharmony_ci    -1
887db96d56Sopenharmony_ci    >>> a.default = -1000
897db96d56Sopenharmony_ci    >>> print(a["noway"])
907db96d56Sopenharmony_ci    -1000
917db96d56Sopenharmony_ci    >>> 'default' in dir(a)
927db96d56Sopenharmony_ci    True
937db96d56Sopenharmony_ci    >>> a.x1 = 100
947db96d56Sopenharmony_ci    >>> a.x2 = 200
957db96d56Sopenharmony_ci    >>> print(a.x1)
967db96d56Sopenharmony_ci    100
977db96d56Sopenharmony_ci    >>> d = dir(a)
987db96d56Sopenharmony_ci    >>> 'default' in d and 'x1' in d and 'x2' in d
997db96d56Sopenharmony_ci    True
1007db96d56Sopenharmony_ci    >>> print(sortdict(a.__dict__))
1017db96d56Sopenharmony_ci    {'default': -1000, 'x1': 100, 'x2': 200}
1027db96d56Sopenharmony_ci    >>>
1037db96d56Sopenharmony_ci"""
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ciclass defaultdict2(dict):
1067db96d56Sopenharmony_ci    __slots__ = ['default']
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_ci    def __init__(self, default=None):
1097db96d56Sopenharmony_ci        dict.__init__(self)
1107db96d56Sopenharmony_ci        self.default = default
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci    def __getitem__(self, key):
1137db96d56Sopenharmony_ci        try:
1147db96d56Sopenharmony_ci            return dict.__getitem__(self, key)
1157db96d56Sopenharmony_ci        except KeyError:
1167db96d56Sopenharmony_ci            return self.default
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci    def get(self, key, *args):
1197db96d56Sopenharmony_ci        if not args:
1207db96d56Sopenharmony_ci            args = (self.default,)
1217db96d56Sopenharmony_ci        return dict.get(self, key, *args)
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ci    def merge(self, other):
1247db96d56Sopenharmony_ci        for key in other:
1257db96d56Sopenharmony_ci            if key not in self:
1267db96d56Sopenharmony_ci                self[key] = other[key]
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_citest_2 = """
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ciThe __slots__ declaration takes a list of instance variables, and reserves
1317db96d56Sopenharmony_cispace for exactly these in the instance. When __slots__ is used, other
1327db96d56Sopenharmony_ciinstance variables cannot be assigned to:
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci    >>> a = defaultdict2(default=0.0)
1357db96d56Sopenharmony_ci    >>> a[1]
1367db96d56Sopenharmony_ci    0.0
1377db96d56Sopenharmony_ci    >>> a.default = -1
1387db96d56Sopenharmony_ci    >>> a[1]
1397db96d56Sopenharmony_ci    -1
1407db96d56Sopenharmony_ci    >>> a.x1 = 1
1417db96d56Sopenharmony_ci    Traceback (most recent call last):
1427db96d56Sopenharmony_ci      File "<stdin>", line 1, in ?
1437db96d56Sopenharmony_ci    AttributeError: 'defaultdict2' object has no attribute 'x1'
1447db96d56Sopenharmony_ci    >>>
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci"""
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_citest_3 = """
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ciIntrospecting instances of built-in types
1517db96d56Sopenharmony_ci
1527db96d56Sopenharmony_ciFor instance of built-in types, x.__class__ is now the same as type(x):
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci    >>> type([])
1557db96d56Sopenharmony_ci    <class 'list'>
1567db96d56Sopenharmony_ci    >>> [].__class__
1577db96d56Sopenharmony_ci    <class 'list'>
1587db96d56Sopenharmony_ci    >>> list
1597db96d56Sopenharmony_ci    <class 'list'>
1607db96d56Sopenharmony_ci    >>> isinstance([], list)
1617db96d56Sopenharmony_ci    True
1627db96d56Sopenharmony_ci    >>> isinstance([], dict)
1637db96d56Sopenharmony_ci    False
1647db96d56Sopenharmony_ci    >>> isinstance([], object)
1657db96d56Sopenharmony_ci    True
1667db96d56Sopenharmony_ci    >>>
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ciYou can get the information from the list type:
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci    >>> pprint.pprint(dir(list))    # like list.__dict__.keys(), but sorted
1717db96d56Sopenharmony_ci    ['__add__',
1727db96d56Sopenharmony_ci     '__class__',
1737db96d56Sopenharmony_ci     '__class_getitem__',
1747db96d56Sopenharmony_ci     '__contains__',
1757db96d56Sopenharmony_ci     '__delattr__',
1767db96d56Sopenharmony_ci     '__delitem__',
1777db96d56Sopenharmony_ci     '__dir__',
1787db96d56Sopenharmony_ci     '__doc__',
1797db96d56Sopenharmony_ci     '__eq__',
1807db96d56Sopenharmony_ci     '__format__',
1817db96d56Sopenharmony_ci     '__ge__',
1827db96d56Sopenharmony_ci     '__getattribute__',
1837db96d56Sopenharmony_ci     '__getitem__',
1847db96d56Sopenharmony_ci     '__getstate__',
1857db96d56Sopenharmony_ci     '__gt__',
1867db96d56Sopenharmony_ci     '__hash__',
1877db96d56Sopenharmony_ci     '__iadd__',
1887db96d56Sopenharmony_ci     '__imul__',
1897db96d56Sopenharmony_ci     '__init__',
1907db96d56Sopenharmony_ci     '__init_subclass__',
1917db96d56Sopenharmony_ci     '__iter__',
1927db96d56Sopenharmony_ci     '__le__',
1937db96d56Sopenharmony_ci     '__len__',
1947db96d56Sopenharmony_ci     '__lt__',
1957db96d56Sopenharmony_ci     '__mul__',
1967db96d56Sopenharmony_ci     '__ne__',
1977db96d56Sopenharmony_ci     '__new__',
1987db96d56Sopenharmony_ci     '__reduce__',
1997db96d56Sopenharmony_ci     '__reduce_ex__',
2007db96d56Sopenharmony_ci     '__repr__',
2017db96d56Sopenharmony_ci     '__reversed__',
2027db96d56Sopenharmony_ci     '__rmul__',
2037db96d56Sopenharmony_ci     '__setattr__',
2047db96d56Sopenharmony_ci     '__setitem__',
2057db96d56Sopenharmony_ci     '__sizeof__',
2067db96d56Sopenharmony_ci     '__str__',
2077db96d56Sopenharmony_ci     '__subclasshook__',
2087db96d56Sopenharmony_ci     'append',
2097db96d56Sopenharmony_ci     'clear',
2107db96d56Sopenharmony_ci     'copy',
2117db96d56Sopenharmony_ci     'count',
2127db96d56Sopenharmony_ci     'extend',
2137db96d56Sopenharmony_ci     'index',
2147db96d56Sopenharmony_ci     'insert',
2157db96d56Sopenharmony_ci     'pop',
2167db96d56Sopenharmony_ci     'remove',
2177db96d56Sopenharmony_ci     'reverse',
2187db96d56Sopenharmony_ci     'sort']
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ciThe new introspection API gives more information than the old one:  in
2217db96d56Sopenharmony_ciaddition to the regular methods, it also shows the methods that are
2227db96d56Sopenharmony_cinormally invoked through special notations, e.g. __iadd__ (+=), __len__
2237db96d56Sopenharmony_ci(len), __ne__ (!=). You can invoke any method from this list directly:
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci    >>> a = ['tic', 'tac']
2267db96d56Sopenharmony_ci    >>> list.__len__(a)          # same as len(a)
2277db96d56Sopenharmony_ci    2
2287db96d56Sopenharmony_ci    >>> a.__len__()              # ditto
2297db96d56Sopenharmony_ci    2
2307db96d56Sopenharmony_ci    >>> list.append(a, 'toe')    # same as a.append('toe')
2317db96d56Sopenharmony_ci    >>> a
2327db96d56Sopenharmony_ci    ['tic', 'tac', 'toe']
2337db96d56Sopenharmony_ci    >>>
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ciThis is just like it is for user-defined classes.
2367db96d56Sopenharmony_ci"""
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_citest_4 = """
2397db96d56Sopenharmony_ci
2407db96d56Sopenharmony_ciStatic methods and class methods
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_ciThe new introspection API makes it possible to add static methods and class
2437db96d56Sopenharmony_cimethods. Static methods are easy to describe: they behave pretty much like
2447db96d56Sopenharmony_cistatic methods in C++ or Java. Here's an example:
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci    >>> class C:
2477db96d56Sopenharmony_ci    ...
2487db96d56Sopenharmony_ci    ...     @staticmethod
2497db96d56Sopenharmony_ci    ...     def foo(x, y):
2507db96d56Sopenharmony_ci    ...         print("staticmethod", x, y)
2517db96d56Sopenharmony_ci
2527db96d56Sopenharmony_ci    >>> C.foo(1, 2)
2537db96d56Sopenharmony_ci    staticmethod 1 2
2547db96d56Sopenharmony_ci    >>> c = C()
2557db96d56Sopenharmony_ci    >>> c.foo(1, 2)
2567db96d56Sopenharmony_ci    staticmethod 1 2
2577db96d56Sopenharmony_ci
2587db96d56Sopenharmony_ciClass methods use a similar pattern to declare methods that receive an
2597db96d56Sopenharmony_ciimplicit first argument that is the *class* for which they are invoked.
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    >>> class C:
2627db96d56Sopenharmony_ci    ...     @classmethod
2637db96d56Sopenharmony_ci    ...     def foo(cls, y):
2647db96d56Sopenharmony_ci    ...         print("classmethod", cls, y)
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci    >>> C.foo(1)
2677db96d56Sopenharmony_ci    classmethod <class 'test.test_descrtut.C'> 1
2687db96d56Sopenharmony_ci    >>> c = C()
2697db96d56Sopenharmony_ci    >>> c.foo(1)
2707db96d56Sopenharmony_ci    classmethod <class 'test.test_descrtut.C'> 1
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_ci    >>> class D(C):
2737db96d56Sopenharmony_ci    ...     pass
2747db96d56Sopenharmony_ci
2757db96d56Sopenharmony_ci    >>> D.foo(1)
2767db96d56Sopenharmony_ci    classmethod <class 'test.test_descrtut.D'> 1
2777db96d56Sopenharmony_ci    >>> d = D()
2787db96d56Sopenharmony_ci    >>> d.foo(1)
2797db96d56Sopenharmony_ci    classmethod <class 'test.test_descrtut.D'> 1
2807db96d56Sopenharmony_ci
2817db96d56Sopenharmony_ciThis prints "classmethod __main__.D 1" both times; in other words, the
2827db96d56Sopenharmony_ciclass passed as the first argument of foo() is the class involved in the
2837db96d56Sopenharmony_cicall, not the class involved in the definition of foo().
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_ciBut notice this:
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci    >>> class E(C):
2887db96d56Sopenharmony_ci    ...     @classmethod
2897db96d56Sopenharmony_ci    ...     def foo(cls, y): # override C.foo
2907db96d56Sopenharmony_ci    ...         print("E.foo() called")
2917db96d56Sopenharmony_ci    ...         C.foo(y)
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci    >>> E.foo(1)
2947db96d56Sopenharmony_ci    E.foo() called
2957db96d56Sopenharmony_ci    classmethod <class 'test.test_descrtut.C'> 1
2967db96d56Sopenharmony_ci    >>> e = E()
2977db96d56Sopenharmony_ci    >>> e.foo(1)
2987db96d56Sopenharmony_ci    E.foo() called
2997db96d56Sopenharmony_ci    classmethod <class 'test.test_descrtut.C'> 1
3007db96d56Sopenharmony_ci
3017db96d56Sopenharmony_ciIn this example, the call to C.foo() from E.foo() will see class C as its
3027db96d56Sopenharmony_cifirst argument, not class E. This is to be expected, since the call
3037db96d56Sopenharmony_cispecifies the class C. But it stresses the difference between these class
3047db96d56Sopenharmony_cimethods and methods defined in metaclasses (where an upcall to a metamethod
3057db96d56Sopenharmony_ciwould pass the target class as an explicit first argument).
3067db96d56Sopenharmony_ci"""
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_citest_5 = """
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ciAttributes defined by get/set methods
3117db96d56Sopenharmony_ci
3127db96d56Sopenharmony_ci
3137db96d56Sopenharmony_ci    >>> class property(object):
3147db96d56Sopenharmony_ci    ...
3157db96d56Sopenharmony_ci    ...     def __init__(self, get, set=None):
3167db96d56Sopenharmony_ci    ...         self.__get = get
3177db96d56Sopenharmony_ci    ...         self.__set = set
3187db96d56Sopenharmony_ci    ...
3197db96d56Sopenharmony_ci    ...     def __get__(self, inst, type=None):
3207db96d56Sopenharmony_ci    ...         return self.__get(inst)
3217db96d56Sopenharmony_ci    ...
3227db96d56Sopenharmony_ci    ...     def __set__(self, inst, value):
3237db96d56Sopenharmony_ci    ...         if self.__set is None:
3247db96d56Sopenharmony_ci    ...             raise AttributeError("this attribute is read-only")
3257db96d56Sopenharmony_ci    ...         return self.__set(inst, value)
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ciNow let's define a class with an attribute x defined by a pair of methods,
3287db96d56Sopenharmony_cigetx() and setx():
3297db96d56Sopenharmony_ci
3307db96d56Sopenharmony_ci    >>> class C(object):
3317db96d56Sopenharmony_ci    ...
3327db96d56Sopenharmony_ci    ...     def __init__(self):
3337db96d56Sopenharmony_ci    ...         self.__x = 0
3347db96d56Sopenharmony_ci    ...
3357db96d56Sopenharmony_ci    ...     def getx(self):
3367db96d56Sopenharmony_ci    ...         return self.__x
3377db96d56Sopenharmony_ci    ...
3387db96d56Sopenharmony_ci    ...     def setx(self, x):
3397db96d56Sopenharmony_ci    ...         if x < 0: x = 0
3407db96d56Sopenharmony_ci    ...         self.__x = x
3417db96d56Sopenharmony_ci    ...
3427db96d56Sopenharmony_ci    ...     x = property(getx, setx)
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ciHere's a small demonstration:
3457db96d56Sopenharmony_ci
3467db96d56Sopenharmony_ci    >>> a = C()
3477db96d56Sopenharmony_ci    >>> a.x = 10
3487db96d56Sopenharmony_ci    >>> print(a.x)
3497db96d56Sopenharmony_ci    10
3507db96d56Sopenharmony_ci    >>> a.x = -10
3517db96d56Sopenharmony_ci    >>> print(a.x)
3527db96d56Sopenharmony_ci    0
3537db96d56Sopenharmony_ci    >>>
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ciHmm -- property is builtin now, so let's try it that way too.
3567db96d56Sopenharmony_ci
3577db96d56Sopenharmony_ci    >>> del property  # unmask the builtin
3587db96d56Sopenharmony_ci    >>> property
3597db96d56Sopenharmony_ci    <class 'property'>
3607db96d56Sopenharmony_ci
3617db96d56Sopenharmony_ci    >>> class C(object):
3627db96d56Sopenharmony_ci    ...     def __init__(self):
3637db96d56Sopenharmony_ci    ...         self.__x = 0
3647db96d56Sopenharmony_ci    ...     def getx(self):
3657db96d56Sopenharmony_ci    ...         return self.__x
3667db96d56Sopenharmony_ci    ...     def setx(self, x):
3677db96d56Sopenharmony_ci    ...         if x < 0: x = 0
3687db96d56Sopenharmony_ci    ...         self.__x = x
3697db96d56Sopenharmony_ci    ...     x = property(getx, setx)
3707db96d56Sopenharmony_ci
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci    >>> a = C()
3737db96d56Sopenharmony_ci    >>> a.x = 10
3747db96d56Sopenharmony_ci    >>> print(a.x)
3757db96d56Sopenharmony_ci    10
3767db96d56Sopenharmony_ci    >>> a.x = -10
3777db96d56Sopenharmony_ci    >>> print(a.x)
3787db96d56Sopenharmony_ci    0
3797db96d56Sopenharmony_ci    >>>
3807db96d56Sopenharmony_ci"""
3817db96d56Sopenharmony_ci
3827db96d56Sopenharmony_citest_6 = """
3837db96d56Sopenharmony_ci
3847db96d56Sopenharmony_ciMethod resolution order
3857db96d56Sopenharmony_ci
3867db96d56Sopenharmony_ciThis example is implicit in the writeup.
3877db96d56Sopenharmony_ci
3887db96d56Sopenharmony_ci>>> class A:    # implicit new-style class
3897db96d56Sopenharmony_ci...     def save(self):
3907db96d56Sopenharmony_ci...         print("called A.save()")
3917db96d56Sopenharmony_ci>>> class B(A):
3927db96d56Sopenharmony_ci...     pass
3937db96d56Sopenharmony_ci>>> class C(A):
3947db96d56Sopenharmony_ci...     def save(self):
3957db96d56Sopenharmony_ci...         print("called C.save()")
3967db96d56Sopenharmony_ci>>> class D(B, C):
3977db96d56Sopenharmony_ci...     pass
3987db96d56Sopenharmony_ci
3997db96d56Sopenharmony_ci>>> D().save()
4007db96d56Sopenharmony_cicalled C.save()
4017db96d56Sopenharmony_ci
4027db96d56Sopenharmony_ci>>> class A(object):  # explicit new-style class
4037db96d56Sopenharmony_ci...     def save(self):
4047db96d56Sopenharmony_ci...         print("called A.save()")
4057db96d56Sopenharmony_ci>>> class B(A):
4067db96d56Sopenharmony_ci...     pass
4077db96d56Sopenharmony_ci>>> class C(A):
4087db96d56Sopenharmony_ci...     def save(self):
4097db96d56Sopenharmony_ci...         print("called C.save()")
4107db96d56Sopenharmony_ci>>> class D(B, C):
4117db96d56Sopenharmony_ci...     pass
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_ci>>> D().save()
4147db96d56Sopenharmony_cicalled C.save()
4157db96d56Sopenharmony_ci"""
4167db96d56Sopenharmony_ci
4177db96d56Sopenharmony_ciclass A(object):
4187db96d56Sopenharmony_ci    def m(self):
4197db96d56Sopenharmony_ci        return "A"
4207db96d56Sopenharmony_ci
4217db96d56Sopenharmony_ciclass B(A):
4227db96d56Sopenharmony_ci    def m(self):
4237db96d56Sopenharmony_ci        return "B" + super(B, self).m()
4247db96d56Sopenharmony_ci
4257db96d56Sopenharmony_ciclass C(A):
4267db96d56Sopenharmony_ci    def m(self):
4277db96d56Sopenharmony_ci        return "C" + super(C, self).m()
4287db96d56Sopenharmony_ci
4297db96d56Sopenharmony_ciclass D(C, B):
4307db96d56Sopenharmony_ci    def m(self):
4317db96d56Sopenharmony_ci        return "D" + super(D, self).m()
4327db96d56Sopenharmony_ci
4337db96d56Sopenharmony_ci
4347db96d56Sopenharmony_citest_7 = """
4357db96d56Sopenharmony_ci
4367db96d56Sopenharmony_ciCooperative methods and "super"
4377db96d56Sopenharmony_ci
4387db96d56Sopenharmony_ci>>> print(D().m()) # "DCBA"
4397db96d56Sopenharmony_ciDCBA
4407db96d56Sopenharmony_ci"""
4417db96d56Sopenharmony_ci
4427db96d56Sopenharmony_citest_8 = """
4437db96d56Sopenharmony_ci
4447db96d56Sopenharmony_ciBackwards incompatibilities
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci>>> class A:
4477db96d56Sopenharmony_ci...     def foo(self):
4487db96d56Sopenharmony_ci...         print("called A.foo()")
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_ci>>> class B(A):
4517db96d56Sopenharmony_ci...     pass
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_ci>>> class C(A):
4547db96d56Sopenharmony_ci...     def foo(self):
4557db96d56Sopenharmony_ci...         B.foo(self)
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci>>> C().foo()
4587db96d56Sopenharmony_cicalled A.foo()
4597db96d56Sopenharmony_ci
4607db96d56Sopenharmony_ci>>> class C(A):
4617db96d56Sopenharmony_ci...     def foo(self):
4627db96d56Sopenharmony_ci...         A.foo(self)
4637db96d56Sopenharmony_ci>>> C().foo()
4647db96d56Sopenharmony_cicalled A.foo()
4657db96d56Sopenharmony_ci"""
4667db96d56Sopenharmony_ci
4677db96d56Sopenharmony_ci__test__ = {"tut1": test_1,
4687db96d56Sopenharmony_ci            "tut2": test_2,
4697db96d56Sopenharmony_ci            "tut3": test_3,
4707db96d56Sopenharmony_ci            "tut4": test_4,
4717db96d56Sopenharmony_ci            "tut5": test_5,
4727db96d56Sopenharmony_ci            "tut6": test_6,
4737db96d56Sopenharmony_ci            "tut7": test_7,
4747db96d56Sopenharmony_ci            "tut8": test_8}
4757db96d56Sopenharmony_ci
4767db96d56Sopenharmony_cidef load_tests(loader, tests, pattern):
4777db96d56Sopenharmony_ci    tests.addTest(doctest.DocTestSuite())
4787db96d56Sopenharmony_ci    return tests
4797db96d56Sopenharmony_ci
4807db96d56Sopenharmony_ci
4817db96d56Sopenharmony_ciif __name__ == "__main__":
4827db96d56Sopenharmony_ci    unittest.main()
483