Add more tests for the descriptor tutorial (GH-25164)

This commit is contained in:
Raymond Hettinger 2021-04-03 13:07:52 -07:00 committed by GitHub
parent b2a91e0c9e
commit e4c8895ee5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 57 additions and 7 deletions

View File

@ -281,7 +281,9 @@ The new class now logs access to both *name* and *age*:
INFO:root:Updating 'name' to 'Catherine C'
INFO:root:Updating 'age' to 20
The two *Person* instances contain only the private names::
The two *Person* instances contain only the private names:
.. doctest::
>>> vars(pete)
{'_name': 'Peter P', '_age': 10}
@ -710,6 +712,38 @@ perform attribute lookup by way of a helper function:
raise
return type(obj).__getattr__(obj, name) # __getattr__
.. doctest::
:hide:
>>> class ClassWithGetAttr:
... x = 123
... def __getattr__(self, attr):
... return attr.upper()
...
>>> cw = ClassWithGetAttr()
>>> cw.y = 456
>>> getattr_hook(cw, 'x')
123
>>> getattr_hook(cw, 'y')
456
>>> getattr_hook(cw, 'z')
'Z'
>>> class ClassWithoutGetAttr:
... x = 123
...
>>> cwo = ClassWithoutGetAttr()
>>> cwo.y = 456
>>> getattr_hook(cwo, 'x')
123
>>> getattr_hook(cwo, 'y')
456
>>> getattr_hook(cwo, 'z')
Traceback (most recent call last):
...
AttributeError: 'ClassWithoutGetAttr' object has no attribute 'z'
So if :meth:`__getattr__` exists, it is called whenever :meth:`__getattribute__`
raises :exc:`AttributeError` (either directly or in one of the descriptor calls).
@ -1139,8 +1173,8 @@ If you have ever wondered where *self* comes from in regular methods or where
*cls* comes from in class methods, this is it!
Other kinds of methods
----------------------
Kinds of methods
----------------
Non-data descriptors provide a simple mechanism for variations on the usual
patterns of binding functions into methods.
@ -1193,19 +1227,19 @@ example calls are unexciting:
class E:
@staticmethod
def f(x):
print(x)
return x * 10
.. doctest::
>>> E.f(3)
3
30
>>> E().f(3)
3
30
Using the non-data descriptor protocol, a pure Python version of
:func:`staticmethod` would look like this:
.. doctest::
.. testcode::
class StaticMethod:
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
@ -1216,6 +1250,22 @@ Using the non-data descriptor protocol, a pure Python version of
def __get__(self, obj, objtype=None):
return self.f
.. testcode::
:hide:
class E_sim:
@StaticMethod
def f(x):
return x * 10
.. doctest::
:hide:
>>> E_sim.f(3)
30
>>> E_sim().f(3)
30
Class methods
-------------