Home | History | Annotate | Download | only in test
      1 # This contains most of the executable examples from Guido's descr
      2 # tutorial, once at
      3 #
      4 #     http://www.python.org/2.2/descrintro.html
      5 #
      6 # A few examples left implicit in the writeup were fleshed out, a few were
      7 # skipped due to lack of interest (e.g., faking super() by hand isn't
      8 # of much interest anymore), and a few were fiddled to make the output
      9 # deterministic.
     10 
     11 from test.support import sortdict
     12 import pprint
     13 
     14 class defaultdict(dict):
     15     def __init__(self, default=None):
     16         dict.__init__(self)
     17         self.default = default
     18 
     19     def __getitem__(self, key):
     20         try:
     21             return dict.__getitem__(self, key)
     22         except KeyError:
     23             return self.default
     24 
     25     def get(self, key, *args):
     26         if not args:
     27             args = (self.default,)
     28         return dict.get(self, key, *args)
     29 
     30     def merge(self, other):
     31         for key in other:
     32             if key not in self:
     33                 self[key] = other[key]
     34 
     35 test_1 = """
     36 
     37 Here's the new type at work:
     38 
     39     >>> print(defaultdict)              # show our type
     40     <class 'test.test_descrtut.defaultdict'>
     41     >>> print(type(defaultdict))        # its metatype
     42     <class 'type'>
     43     >>> a = defaultdict(default=0.0)    # create an instance
     44     >>> print(a)                        # show the instance
     45     {}
     46     >>> print(type(a))                  # show its type
     47     <class 'test.test_descrtut.defaultdict'>
     48     >>> print(a.__class__)              # show its class
     49     <class 'test.test_descrtut.defaultdict'>
     50     >>> print(type(a) is a.__class__)   # its type is its class
     51     True
     52     >>> a[1] = 3.25                     # modify the instance
     53     >>> print(a)                        # show the new value
     54     {1: 3.25}
     55     >>> print(a[1])                     # show the new item
     56     3.25
     57     >>> print(a[0])                     # a non-existent item
     58     0.0
     59     >>> a.merge({1:100, 2:200})         # use a dict method
     60     >>> print(sortdict(a))              # show the result
     61     {1: 3.25, 2: 200}
     62     >>>
     63 
     64 We can also use the new type in contexts where classic only allows "real"
     65 dictionaries, such as the locals/globals dictionaries for the exec
     66 statement or the built-in function eval():
     67 
     68     >>> print(sorted(a.keys()))
     69     [1, 2]
     70     >>> a['print'] = print              # need the print function here
     71     >>> exec("x = 3; print(x)", a)
     72     3
     73     >>> print(sorted(a.keys(), key=lambda x: (str(type(x)), x)))
     74     [1, 2, '__builtins__', 'print', 'x']
     75     >>> print(a['x'])
     76     3
     77     >>>
     78 
     79 Now I'll show that defaultdict instances have dynamic instance variables,
     80 just like classic classes:
     81 
     82     >>> a.default = -1
     83     >>> print(a["noway"])
     84     -1
     85     >>> a.default = -1000
     86     >>> print(a["noway"])
     87     -1000
     88     >>> 'default' in dir(a)
     89     True
     90     >>> a.x1 = 100
     91     >>> a.x2 = 200
     92     >>> print(a.x1)
     93     100
     94     >>> d = dir(a)
     95     >>> 'default' in d and 'x1' in d and 'x2' in d
     96     True
     97     >>> print(sortdict(a.__dict__))
     98     {'default': -1000, 'x1': 100, 'x2': 200}
     99     >>>
    100 """
    101 
    102 class defaultdict2(dict):
    103     __slots__ = ['default']
    104 
    105     def __init__(self, default=None):
    106         dict.__init__(self)
    107         self.default = default
    108 
    109     def __getitem__(self, key):
    110         try:
    111             return dict.__getitem__(self, key)
    112         except KeyError:
    113             return self.default
    114 
    115     def get(self, key, *args):
    116         if not args:
    117             args = (self.default,)
    118         return dict.get(self, key, *args)
    119 
    120     def merge(self, other):
    121         for key in other:
    122             if key not in self:
    123                 self[key] = other[key]
    124 
    125 test_2 = """
    126 
    127 The __slots__ declaration takes a list of instance variables, and reserves
    128 space for exactly these in the instance. When __slots__ is used, other
    129 instance variables cannot be assigned to:
    130 
    131     >>> a = defaultdict2(default=0.0)
    132     >>> a[1]
    133     0.0
    134     >>> a.default = -1
    135     >>> a[1]
    136     -1
    137     >>> a.x1 = 1
    138     Traceback (most recent call last):
    139       File "<stdin>", line 1, in ?
    140     AttributeError: 'defaultdict2' object has no attribute 'x1'
    141     >>>
    142 
    143 """
    144 
    145 test_3 = """
    146 
    147 Introspecting instances of built-in types
    148 
    149 For instance of built-in types, x.__class__ is now the same as type(x):
    150 
    151     >>> type([])
    152     <class 'list'>
    153     >>> [].__class__
    154     <class 'list'>
    155     >>> list
    156     <class 'list'>
    157     >>> isinstance([], list)
    158     True
    159     >>> isinstance([], dict)
    160     False
    161     >>> isinstance([], object)
    162     True
    163     >>>
    164 
    165 You can get the information from the list type:
    166 
    167     >>> pprint.pprint(dir(list))    # like list.__dict__.keys(), but sorted
    168     ['__add__',
    169      '__class__',
    170      '__contains__',
    171      '__delattr__',
    172      '__delitem__',
    173      '__dir__',
    174      '__doc__',
    175      '__eq__',
    176      '__format__',
    177      '__ge__',
    178      '__getattribute__',
    179      '__getitem__',
    180      '__gt__',
    181      '__hash__',
    182      '__iadd__',
    183      '__imul__',
    184      '__init__',
    185      '__init_subclass__',
    186      '__iter__',
    187      '__le__',
    188      '__len__',
    189      '__lt__',
    190      '__mul__',
    191      '__ne__',
    192      '__new__',
    193      '__reduce__',
    194      '__reduce_ex__',
    195      '__repr__',
    196      '__reversed__',
    197      '__rmul__',
    198      '__setattr__',
    199      '__setitem__',
    200      '__sizeof__',
    201      '__str__',
    202      '__subclasshook__',
    203      'append',
    204      'clear',
    205      'copy',
    206      'count',
    207      'extend',
    208      'index',
    209      'insert',
    210      'pop',
    211      'remove',
    212      'reverse',
    213      'sort']
    214 
    215 The new introspection API gives more information than the old one:  in
    216 addition to the regular methods, it also shows the methods that are
    217 normally invoked through special notations, e.g. __iadd__ (+=), __len__
    218 (len), __ne__ (!=). You can invoke any method from this list directly:
    219 
    220     >>> a = ['tic', 'tac']
    221     >>> list.__len__(a)          # same as len(a)
    222     2
    223     >>> a.__len__()              # ditto
    224     2
    225     >>> list.append(a, 'toe')    # same as a.append('toe')
    226     >>> a
    227     ['tic', 'tac', 'toe']
    228     >>>
    229 
    230 This is just like it is for user-defined classes.
    231 """
    232 
    233 test_4 = """
    234 
    235 Static methods and class methods
    236 
    237 The new introspection API makes it possible to add static methods and class
    238 methods. Static methods are easy to describe: they behave pretty much like
    239 static methods in C++ or Java. Here's an example:
    240 
    241     >>> class C:
    242     ...
    243     ...     @staticmethod
    244     ...     def foo(x, y):
    245     ...         print("staticmethod", x, y)
    246 
    247     >>> C.foo(1, 2)
    248     staticmethod 1 2
    249     >>> c = C()
    250     >>> c.foo(1, 2)
    251     staticmethod 1 2
    252 
    253 Class methods use a similar pattern to declare methods that receive an
    254 implicit first argument that is the *class* for which they are invoked.
    255 
    256     >>> class C:
    257     ...     @classmethod
    258     ...     def foo(cls, y):
    259     ...         print("classmethod", cls, y)
    260 
    261     >>> C.foo(1)
    262     classmethod <class 'test.test_descrtut.C'> 1
    263     >>> c = C()
    264     >>> c.foo(1)
    265     classmethod <class 'test.test_descrtut.C'> 1
    266 
    267     >>> class D(C):
    268     ...     pass
    269 
    270     >>> D.foo(1)
    271     classmethod <class 'test.test_descrtut.D'> 1
    272     >>> d = D()
    273     >>> d.foo(1)
    274     classmethod <class 'test.test_descrtut.D'> 1
    275 
    276 This prints "classmethod __main__.D 1" both times; in other words, the
    277 class passed as the first argument of foo() is the class involved in the
    278 call, not the class involved in the definition of foo().
    279 
    280 But notice this:
    281 
    282     >>> class E(C):
    283     ...     @classmethod
    284     ...     def foo(cls, y): # override C.foo
    285     ...         print("E.foo() called")
    286     ...         C.foo(y)
    287 
    288     >>> E.foo(1)
    289     E.foo() called
    290     classmethod <class 'test.test_descrtut.C'> 1
    291     >>> e = E()
    292     >>> e.foo(1)
    293     E.foo() called
    294     classmethod <class 'test.test_descrtut.C'> 1
    295 
    296 In this example, the call to C.foo() from E.foo() will see class C as its
    297 first argument, not class E. This is to be expected, since the call
    298 specifies the class C. But it stresses the difference between these class
    299 methods and methods defined in metaclasses (where an upcall to a metamethod
    300 would pass the target class as an explicit first argument).
    301 """
    302 
    303 test_5 = """
    304 
    305 Attributes defined by get/set methods
    306 
    307 
    308     >>> class property(object):
    309     ...
    310     ...     def __init__(self, get, set=None):
    311     ...         self.__get = get
    312     ...         self.__set = set
    313     ...
    314     ...     def __get__(self, inst, type=None):
    315     ...         return self.__get(inst)
    316     ...
    317     ...     def __set__(self, inst, value):
    318     ...         if self.__set is None:
    319     ...             raise AttributeError("this attribute is read-only")
    320     ...         return self.__set(inst, value)
    321 
    322 Now let's define a class with an attribute x defined by a pair of methods,
    323 getx() and setx():
    324 
    325     >>> class C(object):
    326     ...
    327     ...     def __init__(self):
    328     ...         self.__x = 0
    329     ...
    330     ...     def getx(self):
    331     ...         return self.__x
    332     ...
    333     ...     def setx(self, x):
    334     ...         if x < 0: x = 0
    335     ...         self.__x = x
    336     ...
    337     ...     x = property(getx, setx)
    338 
    339 Here's a small demonstration:
    340 
    341     >>> a = C()
    342     >>> a.x = 10
    343     >>> print(a.x)
    344     10
    345     >>> a.x = -10
    346     >>> print(a.x)
    347     0
    348     >>>
    349 
    350 Hmm -- property is builtin now, so let's try it that way too.
    351 
    352     >>> del property  # unmask the builtin
    353     >>> property
    354     <class 'property'>
    355 
    356     >>> class C(object):
    357     ...     def __init__(self):
    358     ...         self.__x = 0
    359     ...     def getx(self):
    360     ...         return self.__x
    361     ...     def setx(self, x):
    362     ...         if x < 0: x = 0
    363     ...         self.__x = x
    364     ...     x = property(getx, setx)
    365 
    366 
    367     >>> a = C()
    368     >>> a.x = 10
    369     >>> print(a.x)
    370     10
    371     >>> a.x = -10
    372     >>> print(a.x)
    373     0
    374     >>>
    375 """
    376 
    377 test_6 = """
    378 
    379 Method resolution order
    380 
    381 This example is implicit in the writeup.
    382 
    383 >>> class A:    # implicit new-style class
    384 ...     def save(self):
    385 ...         print("called A.save()")
    386 >>> class B(A):
    387 ...     pass
    388 >>> class C(A):
    389 ...     def save(self):
    390 ...         print("called C.save()")
    391 >>> class D(B, C):
    392 ...     pass
    393 
    394 >>> D().save()
    395 called C.save()
    396 
    397 >>> class A(object):  # explicit new-style class
    398 ...     def save(self):
    399 ...         print("called A.save()")
    400 >>> class B(A):
    401 ...     pass
    402 >>> class C(A):
    403 ...     def save(self):
    404 ...         print("called C.save()")
    405 >>> class D(B, C):
    406 ...     pass
    407 
    408 >>> D().save()
    409 called C.save()
    410 """
    411 
    412 class A(object):
    413     def m(self):
    414         return "A"
    415 
    416 class B(A):
    417     def m(self):
    418         return "B" + super(B, self).m()
    419 
    420 class C(A):
    421     def m(self):
    422         return "C" + super(C, self).m()
    423 
    424 class D(C, B):
    425     def m(self):
    426         return "D" + super(D, self).m()
    427 
    428 
    429 test_7 = """
    430 
    431 Cooperative methods and "super"
    432 
    433 >>> print(D().m()) # "DCBA"
    434 DCBA
    435 """
    436 
    437 test_8 = """
    438 
    439 Backwards incompatibilities
    440 
    441 >>> class A:
    442 ...     def foo(self):
    443 ...         print("called A.foo()")
    444 
    445 >>> class B(A):
    446 ...     pass
    447 
    448 >>> class C(A):
    449 ...     def foo(self):
    450 ...         B.foo(self)
    451 
    452 >>> C().foo()
    453 called A.foo()
    454 
    455 >>> class C(A):
    456 ...     def foo(self):
    457 ...         A.foo(self)
    458 >>> C().foo()
    459 called A.foo()
    460 """
    461 
    462 __test__ = {"tut1": test_1,
    463             "tut2": test_2,
    464             "tut3": test_3,
    465             "tut4": test_4,
    466             "tut5": test_5,
    467             "tut6": test_6,
    468             "tut7": test_7,
    469             "tut8": test_8}
    470 
    471 # Magic test name that regrtest.py invokes *after* importing this module.
    472 # This worms around a bootstrap problem.
    473 # Note that doctest and regrtest both look in sys.argv for a "-v" argument,
    474 # so this works as expected in both ways of running regrtest.
    475 def test_main(verbose=None):
    476     # Obscure:  import this module as test.test_descrtut instead of as
    477     # plain test_descrtut because the name of this module works its way
    478     # into the doctest examples, and unless the full test.test_descrtut
    479     # business is used the name can change depending on how the test is
    480     # invoked.
    481     from test import support, test_descrtut
    482     support.run_doctest(test_descrtut, verbose)
    483 
    484 # This part isn't needed for regrtest, but for running the test directly.
    485 if __name__ == "__main__":
    486     test_main(1)
    487