mirror of https://github.com/python/cpython.git
Add more tests for the descriptor tutorial (GH-25164)
This commit is contained in:
parent
b2a91e0c9e
commit
e4c8895ee5
|
@ -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
|
||||
-------------
|
||||
|
|
Loading…
Reference in New Issue