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