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