(root)/
Python-3.11.7/
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 pprint
      13  import doctest
      14  import unittest
      15  
      16  
      17  class ESC[4;38;5;81mdefaultdict(ESC[4;38;5;149mdict):
      18      def __init__(self, default=None):
      19          dict.__init__(self)
      20          self.default = default
      21  
      22      def __getitem__(self, key):
      23          try:
      24              return dict.__getitem__(self, key)
      25          except KeyError:
      26              return self.default
      27  
      28      def get(self, key, *args):
      29          if not args:
      30              args = (self.default,)
      31          return dict.get(self, key, *args)
      32  
      33      def merge(self, other):
      34          for key in other:
      35              if key not in self:
      36                  self[key] = other[key]
      37  
      38  test_1 = """
      39  
      40  Here's the new type at work:
      41  
      42      >>> print(defaultdict)              # show our type
      43      <class 'test.test_descrtut.defaultdict'>
      44      >>> print(type(defaultdict))        # its metatype
      45      <class 'type'>
      46      >>> a = defaultdict(default=0.0)    # create an instance
      47      >>> print(a)                        # show the instance
      48      {}
      49      >>> print(type(a))                  # show its type
      50      <class 'test.test_descrtut.defaultdict'>
      51      >>> print(a.__class__)              # show its class
      52      <class 'test.test_descrtut.defaultdict'>
      53      >>> print(type(a) is a.__class__)   # its type is its class
      54      True
      55      >>> a[1] = 3.25                     # modify the instance
      56      >>> print(a)                        # show the new value
      57      {1: 3.25}
      58      >>> print(a[1])                     # show the new item
      59      3.25
      60      >>> print(a[0])                     # a non-existent item
      61      0.0
      62      >>> a.merge({1:100, 2:200})         # use a dict method
      63      >>> print(sortdict(a))              # show the result
      64      {1: 3.25, 2: 200}
      65      >>>
      66  
      67  We can also use the new type in contexts where classic only allows "real"
      68  dictionaries, such as the locals/globals dictionaries for the exec
      69  statement or the built-in function eval():
      70  
      71      >>> print(sorted(a.keys()))
      72      [1, 2]
      73      >>> a['print'] = print              # need the print function here
      74      >>> exec("x = 3; print(x)", a)
      75      3
      76      >>> print(sorted(a.keys(), key=lambda x: (str(type(x)), x)))
      77      [1, 2, '__builtins__', 'print', 'x']
      78      >>> print(a['x'])
      79      3
      80      >>>
      81  
      82  Now I'll show that defaultdict instances have dynamic instance variables,
      83  just like classic classes:
      84  
      85      >>> a.default = -1
      86      >>> print(a["noway"])
      87      -1
      88      >>> a.default = -1000
      89      >>> print(a["noway"])
      90      -1000
      91      >>> 'default' in dir(a)
      92      True
      93      >>> a.x1 = 100
      94      >>> a.x2 = 200
      95      >>> print(a.x1)
      96      100
      97      >>> d = dir(a)
      98      >>> 'default' in d and 'x1' in d and 'x2' in d
      99      True
     100      >>> print(sortdict(a.__dict__))
     101      {'default': -1000, 'x1': 100, 'x2': 200}
     102      >>>
     103  """
     104  
     105  class ESC[4;38;5;81mdefaultdict2(ESC[4;38;5;149mdict):
     106      __slots__ = ['default']
     107  
     108      def __init__(self, default=None):
     109          dict.__init__(self)
     110          self.default = default
     111  
     112      def __getitem__(self, key):
     113          try:
     114              return dict.__getitem__(self, key)
     115          except KeyError:
     116              return self.default
     117  
     118      def get(self, key, *args):
     119          if not args:
     120              args = (self.default,)
     121          return dict.get(self, key, *args)
     122  
     123      def merge(self, other):
     124          for key in other:
     125              if key not in self:
     126                  self[key] = other[key]
     127  
     128  test_2 = """
     129  
     130  The __slots__ declaration takes a list of instance variables, and reserves
     131  space for exactly these in the instance. When __slots__ is used, other
     132  instance variables cannot be assigned to:
     133  
     134      >>> a = defaultdict2(default=0.0)
     135      >>> a[1]
     136      0.0
     137      >>> a.default = -1
     138      >>> a[1]
     139      -1
     140      >>> a.x1 = 1
     141      Traceback (most recent call last):
     142        File "<stdin>", line 1, in ?
     143      AttributeError: 'defaultdict2' object has no attribute 'x1'
     144      >>>
     145  
     146  """
     147  
     148  test_3 = """
     149  
     150  Introspecting instances of built-in types
     151  
     152  For instance of built-in types, x.__class__ is now the same as type(x):
     153  
     154      >>> type([])
     155      <class 'list'>
     156      >>> [].__class__
     157      <class 'list'>
     158      >>> list
     159      <class 'list'>
     160      >>> isinstance([], list)
     161      True
     162      >>> isinstance([], dict)
     163      False
     164      >>> isinstance([], object)
     165      True
     166      >>>
     167  
     168  You can get the information from the list type:
     169  
     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()