PyXR

c:\python24\lib \ test \ test_descrtut.py



0001 # This contains most of the executable examples from Guido's descr
0002 # tutorial, once at
0003 #
0004 #     http://www.python.org/2.2/descrintro.html
0005 #
0006 # A few examples left implicit in the writeup were fleshed out, a few were
0007 # skipped due to lack of interest (e.g., faking super() by hand isn't
0008 # of much interest anymore), and a few were fiddled to make the output
0009 # deterministic.
0010 
0011 from test.test_support import sortdict
0012 import pprint
0013 
0014 class defaultdict(dict):
0015     def __init__(self, default=None):
0016         dict.__init__(self)
0017         self.default = default
0018 
0019     def __getitem__(self, key):
0020         try:
0021             return dict.__getitem__(self, key)
0022         except KeyError:
0023             return self.default
0024 
0025     def get(self, key, *args):
0026         if not args:
0027             args = (self.default,)
0028         return dict.get(self, key, *args)
0029 
0030     def merge(self, other):
0031         for key in other:
0032             if key not in self:
0033                 self[key] = other[key]
0034 
0035 test_1 = """
0036 
0037 Here's the new type at work:
0038 
0039     >>> print defaultdict               # show our type
0040     <class 'test.test_descrtut.defaultdict'>
0041     >>> print type(defaultdict)         # its metatype
0042     <type 'type'>
0043     >>> a = defaultdict(default=0.0)    # create an instance
0044     >>> print a                         # show the instance
0045     {}
0046     >>> print type(a)                   # show its type
0047     <class 'test.test_descrtut.defaultdict'>
0048     >>> print a.__class__               # show its class
0049     <class 'test.test_descrtut.defaultdict'>
0050     >>> print type(a) is a.__class__    # its type is its class
0051     True
0052     >>> a[1] = 3.25                     # modify the instance
0053     >>> print a                         # show the new value
0054     {1: 3.25}
0055     >>> print a[1]                      # show the new item
0056     3.25
0057     >>> print a[0]                      # a non-existant item
0058     0.0
0059     >>> a.merge({1:100, 2:200})         # use a dict method
0060     >>> print sortdict(a)               # show the result
0061     {1: 3.25, 2: 200}
0062     >>>
0063 
0064 We can also use the new type in contexts where classic only allows "real"
0065 dictionaries, such as the locals/globals dictionaries for the exec
0066 statement or the built-in function eval():
0067 
0068     >>> def sorted(seq):
0069     ...     seq.sort()
0070     ...     return seq
0071     >>> print sorted(a.keys())
0072     [1, 2]
0073     >>> exec "x = 3; print x" in a
0074     3
0075     >>> print sorted(a.keys())
0076     [1, 2, '__builtins__', 'x']
0077     >>> print a['x']
0078     3
0079     >>>
0080 
0081 Now I'll show that defaultdict instances have dynamic instance variables,
0082 just like classic classes:
0083 
0084     >>> a.default = -1
0085     >>> print a["noway"]
0086     -1
0087     >>> a.default = -1000
0088     >>> print a["noway"]
0089     -1000
0090     >>> 'default' in dir(a)
0091     True
0092     >>> a.x1 = 100
0093     >>> a.x2 = 200
0094     >>> print a.x1
0095     100
0096     >>> d = dir(a)
0097     >>> 'default' in d and 'x1' in d and 'x2' in d
0098     True
0099     >>> print sortdict(a.__dict__)
0100     {'default': -1000, 'x1': 100, 'x2': 200}
0101     >>>
0102 """
0103 
0104 class defaultdict2(dict):
0105     __slots__ = ['default']
0106 
0107     def __init__(self, default=None):
0108         dict.__init__(self)
0109         self.default = default
0110 
0111     def __getitem__(self, key):
0112         try:
0113             return dict.__getitem__(self, key)
0114         except KeyError:
0115             return self.default
0116 
0117     def get(self, key, *args):
0118         if not args:
0119             args = (self.default,)
0120         return dict.get(self, key, *args)
0121 
0122     def merge(self, other):
0123         for key in other:
0124             if key not in self:
0125                 self[key] = other[key]
0126 
0127 test_2 = """
0128 
0129 The __slots__ declaration takes a list of instance variables, and reserves
0130 space for exactly these in the instance. When __slots__ is used, other
0131 instance variables cannot be assigned to:
0132 
0133     >>> a = defaultdict2(default=0.0)
0134     >>> a[1]
0135     0.0
0136     >>> a.default = -1
0137     >>> a[1]
0138     -1
0139     >>> a.x1 = 1
0140     Traceback (most recent call last):
0141       File "<stdin>", line 1, in ?
0142     AttributeError: 'defaultdict2' object has no attribute 'x1'
0143     >>>
0144 
0145 """
0146 
0147 test_3 = """
0148 
0149 Introspecting instances of built-in types
0150 
0151 For instance of built-in types, x.__class__ is now the same as type(x):
0152 
0153     >>> type([])
0154     <type 'list'>
0155     >>> [].__class__
0156     <type 'list'>
0157     >>> list
0158     <type 'list'>
0159     >>> isinstance([], list)
0160     True
0161     >>> isinstance([], dict)
0162     False
0163     >>> isinstance([], object)
0164     True
0165     >>>
0166 
0167 Under the new proposal, the __methods__ attribute no longer exists:
0168 
0169     >>> [].__methods__
0170     Traceback (most recent call last):
0171       File "<stdin>", line 1, in ?
0172     AttributeError: 'list' object has no attribute '__methods__'
0173     >>>
0174 
0175 Instead, you can get the same information from the list type:
0176 
0177     >>> pprint.pprint(dir(list))    # like list.__dict__.keys(), but sorted
0178     ['__add__',
0179      '__class__',
0180      '__contains__',
0181      '__delattr__',
0182      '__delitem__',
0183      '__delslice__',
0184      '__doc__',
0185      '__eq__',
0186      '__ge__',
0187      '__getattribute__',
0188      '__getitem__',
0189      '__getslice__',
0190      '__gt__',
0191      '__hash__',
0192      '__iadd__',
0193      '__imul__',
0194      '__init__',
0195      '__iter__',
0196      '__le__',
0197      '__len__',
0198      '__lt__',
0199      '__mul__',
0200      '__ne__',
0201      '__new__',
0202      '__reduce__',
0203      '__reduce_ex__',
0204      '__repr__',
0205      '__reversed__',
0206      '__rmul__',
0207      '__setattr__',
0208      '__setitem__',
0209      '__setslice__',
0210      '__str__',
0211      'append',
0212      'count',
0213      'extend',
0214      'index',
0215      'insert',
0216      'pop',
0217      'remove',
0218      'reverse',
0219      'sort']
0220 
0221 The new introspection API gives more information than the old one:  in
0222 addition to the regular methods, it also shows the methods that are
0223 normally invoked through special notations, e.g. __iadd__ (+=), __len__
0224 (len), __ne__ (!=). You can invoke any method from this list directly:
0225 
0226     >>> a = ['tic', 'tac']
0227     >>> list.__len__(a)          # same as len(a)
0228     2
0229     >>> a.__len__()              # ditto
0230     2
0231     >>> list.append(a, 'toe')    # same as a.append('toe')
0232     >>> a
0233     ['tic', 'tac', 'toe']
0234     >>>
0235 
0236 This is just like it is for user-defined classes.
0237 """
0238 
0239 test_4 = """
0240 
0241 Static methods and class methods
0242 
0243 The new introspection API makes it possible to add static methods and class
0244 methods. Static methods are easy to describe: they behave pretty much like
0245 static methods in C++ or Java. Here's an example:
0246 
0247     >>> class C:
0248     ...
0249     ...     def foo(x, y):
0250     ...         print "staticmethod", x, y
0251     ...     foo = staticmethod(foo)
0252 
0253     >>> C.foo(1, 2)
0254     staticmethod 1 2
0255     >>> c = C()
0256     >>> c.foo(1, 2)
0257     staticmethod 1 2
0258 
0259 Class methods use a similar pattern to declare methods that receive an
0260 implicit first argument that is the *class* for which they are invoked.
0261 
0262     >>> class C:
0263     ...     def foo(cls, y):
0264     ...         print "classmethod", cls, y
0265     ...     foo = classmethod(foo)
0266 
0267     >>> C.foo(1)
0268     classmethod test.test_descrtut.C 1
0269     >>> c = C()
0270     >>> c.foo(1)
0271     classmethod test.test_descrtut.C 1
0272 
0273     >>> class D(C):
0274     ...     pass
0275 
0276     >>> D.foo(1)
0277     classmethod test.test_descrtut.D 1
0278     >>> d = D()
0279     >>> d.foo(1)
0280     classmethod test.test_descrtut.D 1
0281 
0282 This prints "classmethod __main__.D 1" both times; in other words, the
0283 class passed as the first argument of foo() is the class involved in the
0284 call, not the class involved in the definition of foo().
0285 
0286 But notice this:
0287 
0288     >>> class E(C):
0289     ...     def foo(cls, y): # override C.foo
0290     ...         print "E.foo() called"
0291     ...         C.foo(y)
0292     ...     foo = classmethod(foo)
0293 
0294     >>> E.foo(1)
0295     E.foo() called
0296     classmethod test.test_descrtut.C 1
0297     >>> e = E()
0298     >>> e.foo(1)
0299     E.foo() called
0300     classmethod test.test_descrtut.C 1
0301 
0302 In this example, the call to C.foo() from E.foo() will see class C as its
0303 first argument, not class E. This is to be expected, since the call
0304 specifies the class C. But it stresses the difference between these class
0305 methods and methods defined in metaclasses (where an upcall to a metamethod
0306 would pass the target class as an explicit first argument).
0307 """
0308 
0309 test_5 = """
0310 
0311 Attributes defined by get/set methods
0312 
0313 
0314     >>> class property(object):
0315     ...
0316     ...     def __init__(self, get, set=None):
0317     ...         self.__get = get
0318     ...         self.__set = set
0319     ...
0320     ...     def __get__(self, inst, type=None):
0321     ...         return self.__get(inst)
0322     ...
0323     ...     def __set__(self, inst, value):
0324     ...         if self.__set is None:
0325     ...             raise AttributeError, "this attribute is read-only"
0326     ...         return self.__set(inst, value)
0327 
0328 Now let's define a class with an attribute x defined by a pair of methods,
0329 getx() and and setx():
0330 
0331     >>> class C(object):
0332     ...
0333     ...     def __init__(self):
0334     ...         self.__x = 0
0335     ...
0336     ...     def getx(self):
0337     ...         return self.__x
0338     ...
0339     ...     def setx(self, x):
0340     ...         if x < 0: x = 0
0341     ...         self.__x = x
0342     ...
0343     ...     x = property(getx, setx)
0344 
0345 Here's a small demonstration:
0346 
0347     >>> a = C()
0348     >>> a.x = 10
0349     >>> print a.x
0350     10
0351     >>> a.x = -10
0352     >>> print a.x
0353     0
0354     >>>
0355 
0356 Hmm -- property is builtin now, so let's try it that way too.
0357 
0358     >>> del property  # unmask the builtin
0359     >>> property
0360     <type 'property'>
0361 
0362     >>> class C(object):
0363     ...     def __init__(self):
0364     ...         self.__x = 0
0365     ...     def getx(self):
0366     ...         return self.__x
0367     ...     def setx(self, x):
0368     ...         if x < 0: x = 0
0369     ...         self.__x = x
0370     ...     x = property(getx, setx)
0371 
0372 
0373     >>> a = C()
0374     >>> a.x = 10
0375     >>> print a.x
0376     10
0377     >>> a.x = -10
0378     >>> print a.x
0379     0
0380     >>>
0381 """
0382 
0383 test_6 = """
0384 
0385 Method resolution order
0386 
0387 This example is implicit in the writeup.
0388 
0389 >>> class A:    # classic class
0390 ...     def save(self):
0391 ...         print "called A.save()"
0392 >>> class B(A):
0393 ...     pass
0394 >>> class C(A):
0395 ...     def save(self):
0396 ...         print "called C.save()"
0397 >>> class D(B, C):
0398 ...     pass
0399 
0400 >>> D().save()
0401 called A.save()
0402 
0403 >>> class A(object):  # new class
0404 ...     def save(self):
0405 ...         print "called A.save()"
0406 >>> class B(A):
0407 ...     pass
0408 >>> class C(A):
0409 ...     def save(self):
0410 ...         print "called C.save()"
0411 >>> class D(B, C):
0412 ...     pass
0413 
0414 >>> D().save()
0415 called C.save()
0416 """
0417 
0418 class A(object):
0419     def m(self):
0420         return "A"
0421 
0422 class B(A):
0423     def m(self):
0424         return "B" + super(B, self).m()
0425 
0426 class C(A):
0427     def m(self):
0428         return "C" + super(C, self).m()
0429 
0430 class D(C, B):
0431     def m(self):
0432         return "D" + super(D, self).m()
0433 
0434 
0435 test_7 = """
0436 
0437 Cooperative methods and "super"
0438 
0439 >>> print D().m() # "DCBA"
0440 DCBA
0441 """
0442 
0443 test_8 = """
0444 
0445 Backwards incompatibilities
0446 
0447 >>> class A:
0448 ...     def foo(self):
0449 ...         print "called A.foo()"
0450 
0451 >>> class B(A):
0452 ...     pass
0453 
0454 >>> class C(A):
0455 ...     def foo(self):
0456 ...         B.foo(self)
0457 
0458 >>> C().foo()
0459 Traceback (most recent call last):
0460  ...
0461 TypeError: unbound method foo() must be called with B instance as first argument (got C instance instead)
0462 
0463 >>> class C(A):
0464 ...     def foo(self):
0465 ...         A.foo(self)
0466 >>> C().foo()
0467 called A.foo()
0468 """
0469 
0470 __test__ = {"tut1": test_1,
0471             "tut2": test_2,
0472             "tut3": test_3,
0473             "tut4": test_4,
0474             "tut5": test_5,
0475             "tut6": test_6,
0476             "tut7": test_7,
0477             "tut8": test_8}
0478 
0479 # Magic test name that regrtest.py invokes *after* importing this module.
0480 # This worms around a bootstrap problem.
0481 # Note that doctest and regrtest both look in sys.argv for a "-v" argument,
0482 # so this works as expected in both ways of running regrtest.
0483 def test_main(verbose=None):
0484     # Obscure:  import this module as test.test_descrtut instead of as
0485     # plain test_descrtut because the name of this module works its way
0486     # into the doctest examples, and unless the full test.test_descrtut
0487     # business is used the name can change depending on how the test is
0488     # invoked.
0489     from test import test_support, test_descrtut
0490     test_support.run_doctest(test_descrtut, verbose)
0491 
0492 # This part isn't needed for regrtest, but for running the test directly.
0493 if __name__ == "__main__":
0494     test_main(1)
0495 

Generated by PyXR 0.9.4
SourceForge.net Logo