@@ -13,7 +13,7 @@ Descriptor HowTo Guide
13
13
:term: `Descriptors <descriptor> ` let objects customize attribute lookup,
14
14
storage, and deletion.
15
15
16
- This HowTo guide has three major sections:
16
+ This guide has four major sections:
17
17
18
18
1) The "primer" gives a basic overview, moving gently from simple examples,
19
19
adding one feature at a time. It is a great place to start.
@@ -25,6 +25,11 @@ This HowTo guide has three major sections:
25
25
detailed mechanics of how descriptors work. Most people don't need this
26
26
level of detail.
27
27
28
+ 4) The last section has pure Python equivalents for built-in descriptors that
29
+ are written in C. Read this if you're curious about how functions turn
30
+ into bound methods or about how to implement common tools like
31
+ :func: `classmethod `, :func: `staticmethod `, and :func: `property `.
32
+
28
33
29
34
Primer
30
35
^^^^^^
@@ -99,7 +104,7 @@ different, updated answers each time::
99
104
3
100
105
>>> os.system('touch games/newfile') # Add a fourth file to the directory
101
106
0
102
- >>> g.size
107
+ >>> g.size # Automatically updated
103
108
4
104
109
>>> s.size # The songs directory has twenty files
105
110
20
@@ -197,7 +202,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*::
197
202
198
203
import logging
199
204
200
- logging.basicConfig(level=logging.INFO, force=True )
205
+ logging.basicConfig(level=logging.INFO)
201
206
202
207
class LoggedAccess:
203
208
@@ -259,7 +264,7 @@ A :term:`descriptor` is what we call any object that defines :meth:`__get__`,
259
264
:meth: `__set__ `, or :meth: `__delete__ `.
260
265
261
266
Optionally, descriptors can have a :meth: `__set_name__ ` method. This is only
262
- used in cases where a descriptor needs to know either the class where it is
267
+ used in cases where a descriptor needs to know either the class where it was
263
268
created or the name of class variable it was assigned to.
264
269
265
270
Descriptors get invoked by the dot operator during attribute lookup. If a
@@ -318,7 +323,7 @@ managed attribute descriptor::
318
323
def validate(self, value):
319
324
pass
320
325
321
- Custom validators need to subclass from :class: `Validator ` and supply a
326
+ Custom validators need to inherit from :class: `Validator ` and must supply a
322
327
:meth: `validate ` method to test various restrictions as needed.
323
328
324
329
@@ -334,8 +339,9 @@ Here are three practical data validation utilities:
334
339
minimum or maximum.
335
340
336
341
3) :class: `String ` verifies that a value is a :class: `str `. Optionally, it
337
- validates a given minimum or maximum length. Optionally, it can test for
338
- another predicate as well.
342
+ validates a given minimum or maximum length. It can validate a
343
+ user-defined `predicate
344
+ <https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)> `_ as well.
339
345
340
346
::
341
347
@@ -398,7 +404,7 @@ Here's how the data validators can be used in a real class::
398
404
class Component:
399
405
400
406
name = String(minsize=3, maxsize=10, predicate=str.isupper)
401
- kind = OneOf('plastic ', 'metal')
407
+ kind = OneOf('wood ', 'metal', 'plastic ')
402
408
quantity = Number(minvalue=0)
403
409
404
410
def __init__(self, name, kind, quantity):
@@ -426,9 +432,7 @@ Abstract
426
432
--------
427
433
428
434
Defines descriptors, summarizes the protocol, and shows how descriptors are
429
- called. Examines a custom descriptor and several built-in Python descriptors
430
- including functions, properties, static methods, and class methods. Shows how
431
- each works by giving a pure Python equivalent and a sample application.
435
+ called. Provides an example showing how object relational mappings work.
432
436
433
437
Learning about descriptors not only provides access to a larger toolset, it
434
438
creates a deeper understanding of how Python works and an appreciation for the
@@ -519,34 +523,27 @@ The full C implementation can be found in :c:func:`PyObject_GenericGetAttr()` in
519
523
520
524
It transforms ``A.x `` into ``A.__dict__['x'].__get__(None, A) ``.
521
525
522
- In pure Python, it looks like this::
523
-
524
- def __getattribute__(cls, key):
525
- "Emulate type_getattro() in Objects/typeobject.c"
526
- v = object.__getattribute__(cls, key)
527
- if hasattr(v, '__get__'):
528
- return v.__get__(None, cls)
529
- return v
526
+ The full C implementation can be found in :c:func: `type_getattro() ` in
527
+ :source: `Objects/typeobject.c `.
530
528
531
529
**Super **: The machinery is in the custom :meth: `__getattribute__ ` method for
532
530
object returned by :class: `super() `.
533
531
534
532
The attribute lookup ``super(A, obj).m `` searches ``obj.__class__.__mro__ `` for
535
533
the base class ``B `` immediately following ``A `` and then returns
536
- ``B.__dict__['m'].__get__(obj, A) ``.
537
-
538
- If not a descriptor, ``m `` is returned unchanged. If not in the dictionary,
539
- ``m `` reverts to a search using :meth: `object.__getattribute__ `.
534
+ ``B.__dict__['m'].__get__(obj, A) ``. If not a descriptor, ``m `` is returned
535
+ unchanged. If not in the dictionary, ``m `` reverts to a search using
536
+ :meth: `object.__getattribute__ `.
540
537
541
538
The implementation details are in :c:func: `super_getattro() ` in
542
539
:source: `Objects/typeobject.c `. A pure Python equivalent can be found in
543
540
`Guido's Tutorial `_.
544
541
545
542
.. _`Guido's Tutorial` : https://www.python.org/download/releases/2.2.3/descrintro/#cooperation
546
543
547
- **Summary **: The details listed above show that the mechanism for descriptors is
548
- embedded in the :meth: `__getattribute__() ` methods for :class: `object `,
549
- :class: ` type `, and : func: `super `.
544
+ **Summary **: The mechanism for descriptors is embedded in the
545
+ :meth: `__getattribute__() ` methods for :class: `object `, :class: ` type `, and
546
+ :func: `super `.
550
547
551
548
The important points to remember are:
552
549
@@ -586,15 +583,16 @@ place at the time of class creation. If descriptors are added to the class
586
583
afterwards, :meth: `__set_name__ ` will need to be called manually.
587
584
588
585
589
- Descriptor Example
590
- ------------------
586
+ ORM Example
587
+ -----------
591
588
592
589
The following code is simplified skeleton showing how data descriptors could
593
590
be used to implement an `object relational mapping
594
591
<https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping> `_.
595
592
596
- The essential idea is that instances only hold keys to a database table. The
597
- actual data is stored in an external table that is being dynamically updated::
593
+ The essential idea is that the data is stored in an external database. The
594
+ Python instances only hold keys to the database's tables. Descriptors take
595
+ care of lookups or updates::
598
596
599
597
class Field:
600
598
@@ -609,8 +607,8 @@ actual data is stored in an external table that is being dynamically updated::
609
607
conn.execute(self.store, [value, obj.key])
610
608
conn.commit()
611
609
612
- We can use the :class: `Field ` to define "models" that describe the schema for
613
- each table in a database::
610
+ We can use the :class: `Field ` class to define "models" that describe the schema
611
+ for each table in a database::
614
612
615
613
class Movie:
616
614
table = 'Movies' # Table name
@@ -650,10 +648,13 @@ it can be updated::
650
648
>>> Movie('Star Wars').director
651
649
'J.J. Abrams'
652
650
651
+ Pure Python Equivalents
652
+ ^^^^^^^^^^^^^^^^^^^^^^^
653
+
653
654
The descriptor protocol is simple and offers exciting possibilities. Several
654
- use cases are so common that they have been packaged into individual function
655
- calls. Properties, bound methods, static methods, and class methods are all
656
- based on the descriptor protocol.
655
+ use cases are so common that they have been prepackaged into builtin tools.
656
+ Properties, bound methods, static methods, and class methods are all based on
657
+ the descriptor protocol.
657
658
658
659
659
660
Properties
@@ -746,7 +747,7 @@ prepended to the other arguments. By convention, the instance is called
746
747
Methods can be created manually with :class: `types.MethodType ` which is
747
748
roughly equivalent to::
748
749
749
- class Method :
750
+ class MethodType :
750
751
"Emulate Py_MethodType in Objects/classobject.c"
751
752
752
753
def __init__(self, func, obj):
@@ -770,7 +771,7 @@ during dotted lookup from an instance. Here's how it works::
770
771
"Simulate func_descr_get() in Objects/funcobject.c"
771
772
if obj is None:
772
773
return self
773
- return types. MethodType(self, obj)
774
+ return MethodType(self, obj)
774
775
775
776
Running the following class in the interpreter shows how the function
776
777
descriptor works in practice::
@@ -816,8 +817,8 @@ If you have ever wondered where *self* comes from in regular methods or where
816
817
*cls * comes from in class methods, this is it!
817
818
818
819
819
- Static Methods and Class Methods
820
- --------------------------------
820
+ Static Methods
821
+ --------------
821
822
822
823
Non-data descriptors provide a simple mechanism for variations on the usual
823
824
patterns of binding functions into methods.
@@ -883,6 +884,10 @@ Using the non-data descriptor protocol, a pure Python version of
883
884
def __get__(self, obj, objtype=None):
884
885
return self.f
885
886
887
+
888
+ Class Methods
889
+ -------------
890
+
886
891
Unlike static methods, class methods prepend the class reference to the
887
892
argument list before calling the function. This format is the same
888
893
for whether the caller is an object or a class::
@@ -897,12 +902,11 @@ for whether the caller is an object or a class::
897
902
>>> print(F().f(3))
898
903
('F', 3)
899
904
900
-
901
- This behavior is useful whenever the function only needs to have a class
902
- reference and does not care about any underlying data. One use for
903
- class methods is to create alternate class constructors. The classmethod
904
- :func: `dict.fromkeys ` creates a new dictionary from a list of keys. The pure
905
- Python equivalent is::
905
+ This behavior is useful whenever the method only needs to have a class
906
+ reference and does rely on data stored in a specific instance. One use for
907
+ class methods is to create alternate class constructors. For example, the
908
+ classmethod :func: `dict.fromkeys ` creates a new dictionary from a list of
909
+ keys. The pure Python equivalent is::
906
910
907
911
class Dict:
908
912
...
@@ -934,7 +938,7 @@ Using the non-data descriptor protocol, a pure Python version of
934
938
cls = type(obj)
935
939
if hasattr(obj, '__get__'):
936
940
return self.f.__get__(cls)
937
- return types. MethodType(self.f, cls)
941
+ return MethodType(self.f, cls)
938
942
939
943
The code path for ``hasattr(obj, '__get__') `` was added in Python 3.9 and
940
944
makes it possible for :func: `classmethod ` to support chained decorators.
0 commit comments