1.. _descriptorhowto:
2
3======================
4Descriptor HowTo Guide
5======================
6
7:Author: Raymond Hettinger
8:Contact: <python at rcn dot com>
9
10.. Contents::
11
12
13:term:`Descriptors <descriptor>` let objects customize attribute lookup,
14storage, and deletion.
15
16This guide has four major sections:
17
181) The "primer" gives a basic overview, moving gently from simple examples,
19   adding one feature at a time.  Start here if you're new to descriptors.
20
212) The second section shows a complete, practical descriptor example.  If you
22   already know the basics, start there.
23
243) The third section provides a more technical tutorial that goes into the
25   detailed mechanics of how descriptors work.  Most people don't need this
26   level of detail.
27
284) 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 the implementation of common tools like
31   :func:`classmethod`, :func:`staticmethod`, :func:`property`, and
32   :term:`__slots__`.
33
34
35Primer
36^^^^^^
37
38In this primer, we start with the most basic possible example and then we'll
39add new capabilities one by one.
40
41
42Simple example: A descriptor that returns a constant
43----------------------------------------------------
44
45The :class:`Ten` class is a descriptor whose :meth:`__get__` method always
46returns the constant ``10``:
47
48.. testcode::
49
50    class Ten:
51        def __get__(self, obj, objtype=None):
52            return 10
53
54To use the descriptor, it must be stored as a class variable in another class:
55
56.. testcode::
57
58    class A:
59        x = 5                       # Regular class attribute
60        y = Ten()                   # Descriptor instance
61
62An interactive session shows the difference between normal attribute lookup
63and descriptor lookup:
64
65.. doctest::
66
67    >>> a = A()                     # Make an instance of class A
68    >>> a.x                         # Normal attribute lookup
69    5
70    >>> a.y                         # Descriptor lookup
71    10
72
73In the ``a.x`` attribute lookup, the dot operator finds ``'x': 5``
74in the class dictionary.  In the ``a.y`` lookup, the dot operator
75finds a descriptor instance, recognized by its ``__get__`` method.
76Calling that method returns ``10``.
77
78Note that the value ``10`` is not stored in either the class dictionary or the
79instance dictionary.  Instead, the value ``10`` is computed on demand.
80
81This example shows how a simple descriptor works, but it isn't very useful.
82For retrieving constants, normal attribute lookup would be better.
83
84In the next section, we'll create something more useful, a dynamic lookup.
85
86
87Dynamic lookups
88---------------
89
90Interesting descriptors typically run computations instead of returning
91constants:
92
93.. testcode::
94
95    import os
96
97    class DirectorySize:
98
99        def __get__(self, obj, objtype=None):
100            return len(os.listdir(obj.dirname))
101
102    class Directory:
103
104        size = DirectorySize()              # Descriptor instance
105
106        def __init__(self, dirname):
107            self.dirname = dirname          # Regular instance attribute
108
109An interactive session shows that the lookup is dynamic — it computes
110different, updated answers each time::
111
112    >>> s = Directory('songs')
113    >>> g = Directory('games')
114    >>> s.size                              # The songs directory has twenty files
115    20
116    >>> g.size                              # The games directory has three files
117    3
118    >>> os.remove('games/chess')            # Delete a game
119    >>> g.size                              # File count is automatically updated
120    2
121
122Besides showing how descriptors can run computations, this example also
123reveals the purpose of the parameters to :meth:`__get__`.  The *self*
124parameter is *size*, an instance of *DirectorySize*.  The *obj* parameter is
125either *g* or *s*, an instance of *Directory*.  It is the *obj* parameter that
126lets the :meth:`__get__` method learn the target directory.  The *objtype*
127parameter is the class *Directory*.
128
129
130Managed attributes
131------------------
132
133A popular use for descriptors is managing access to instance data.  The
134descriptor is assigned to a public attribute in the class dictionary while the
135actual data is stored as a private attribute in the instance dictionary.  The
136descriptor's :meth:`__get__` and :meth:`__set__` methods are triggered when
137the public attribute is accessed.
138
139In the following example, *age* is the public attribute and *_age* is the
140private attribute.  When the public attribute is accessed, the descriptor logs
141the lookup or update:
142
143.. testcode::
144
145    import logging
146
147    logging.basicConfig(level=logging.INFO)
148
149    class LoggedAgeAccess:
150
151        def __get__(self, obj, objtype=None):
152            value = obj._age
153            logging.info('Accessing %r giving %r', 'age', value)
154            return value
155
156        def __set__(self, obj, value):
157            logging.info('Updating %r to %r', 'age', value)
158            obj._age = value
159
160    class Person:
161
162        age = LoggedAgeAccess()             # Descriptor instance
163
164        def __init__(self, name, age):
165            self.name = name                # Regular instance attribute
166            self.age = age                  # Calls __set__()
167
168        def birthday(self):
169            self.age += 1                   # Calls both __get__() and __set__()
170
171
172An interactive session shows that all access to the managed attribute *age* is
173logged, but that the regular attribute *name* is not logged:
174
175.. testcode::
176    :hide:
177
178    import logging, sys
179    logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
180
181.. doctest::
182
183    >>> mary = Person('Mary M', 30)         # The initial age update is logged
184    INFO:root:Updating 'age' to 30
185    >>> dave = Person('David D', 40)
186    INFO:root:Updating 'age' to 40
187
188    >>> vars(mary)                          # The actual data is in a private attribute
189    {'name': 'Mary M', '_age': 30}
190    >>> vars(dave)
191    {'name': 'David D', '_age': 40}
192
193    >>> mary.age                            # Access the data and log the lookup
194    INFO:root:Accessing 'age' giving 30
195    30
196    >>> mary.birthday()                     # Updates are logged as well
197    INFO:root:Accessing 'age' giving 30
198    INFO:root:Updating 'age' to 31
199
200    >>> dave.name                           # Regular attribute lookup isn't logged
201    'David D'
202    >>> dave.age                            # Only the managed attribute is logged
203    INFO:root:Accessing 'age' giving 40
204    40
205
206One major issue with this example is that the private name *_age* is hardwired in
207the *LoggedAgeAccess* class.  That means that each instance can only have one
208logged attribute and that its name is unchangeable.  In the next example,
209we'll fix that problem.
210
211
212Customized names
213----------------
214
215When a class uses descriptors, it can inform each descriptor about which
216variable name was used.
217
218In this example, the :class:`Person` class has two descriptor instances,
219*name* and *age*.  When the :class:`Person` class is defined, it makes a
220callback to :meth:`__set_name__` in *LoggedAccess* so that the field names can
221be recorded, giving each descriptor its own *public_name* and *private_name*:
222
223.. testcode::
224
225    import logging
226
227    logging.basicConfig(level=logging.INFO)
228
229    class LoggedAccess:
230
231        def __set_name__(self, owner, name):
232            self.public_name = name
233            self.private_name = '_' + name
234
235        def __get__(self, obj, objtype=None):
236            value = getattr(obj, self.private_name)
237            logging.info('Accessing %r giving %r', self.public_name, value)
238            return value
239
240        def __set__(self, obj, value):
241            logging.info('Updating %r to %r', self.public_name, value)
242            setattr(obj, self.private_name, value)
243
244    class Person:
245
246        name = LoggedAccess()                # First descriptor instance
247        age = LoggedAccess()                 # Second descriptor instance
248
249        def __init__(self, name, age):
250            self.name = name                 # Calls the first descriptor
251            self.age = age                   # Calls the second descriptor
252
253        def birthday(self):
254            self.age += 1
255
256An interactive session shows that the :class:`Person` class has called
257:meth:`__set_name__` so that the field names would be recorded.  Here
258we call :func:`vars` to look up the descriptor without triggering it:
259
260.. doctest::
261
262    >>> vars(vars(Person)['name'])
263    {'public_name': 'name', 'private_name': '_name'}
264    >>> vars(vars(Person)['age'])
265    {'public_name': 'age', 'private_name': '_age'}
266
267The new class now logs access to both *name* and *age*:
268
269.. testcode::
270    :hide:
271
272    import logging, sys
273    logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
274
275.. doctest::
276
277    >>> pete = Person('Peter P', 10)
278    INFO:root:Updating 'name' to 'Peter P'
279    INFO:root:Updating 'age' to 10
280    >>> kate = Person('Catherine C', 20)
281    INFO:root:Updating 'name' to 'Catherine C'
282    INFO:root:Updating 'age' to 20
283
284The two *Person* instances contain only the private names:
285
286.. doctest::
287
288    >>> vars(pete)
289    {'_name': 'Peter P', '_age': 10}
290    >>> vars(kate)
291    {'_name': 'Catherine C', '_age': 20}
292
293
294Closing thoughts
295----------------
296
297A :term:`descriptor` is what we call any object that defines :meth:`__get__`,
298:meth:`__set__`, or :meth:`__delete__`.
299
300Optionally, descriptors can have a :meth:`__set_name__` method.  This is only
301used in cases where a descriptor needs to know either the class where it was
302created or the name of class variable it was assigned to.  (This method, if
303present, is called even if the class is not a descriptor.)
304
305Descriptors get invoked by the dot operator during attribute lookup.  If a
306descriptor is accessed indirectly with ``vars(some_class)[descriptor_name]``,
307the descriptor instance is returned without invoking it.
308
309Descriptors only work when used as class variables.  When put in instances,
310they have no effect.
311
312The main motivation for descriptors is to provide a hook allowing objects
313stored in class variables to control what happens during attribute lookup.
314
315Traditionally, the calling class controls what happens during lookup.
316Descriptors invert that relationship and allow the data being looked-up to
317have a say in the matter.
318
319Descriptors are used throughout the language.  It is how functions turn into
320bound methods.  Common tools like :func:`classmethod`, :func:`staticmethod`,
321:func:`property`, and :func:`functools.cached_property` are all implemented as
322descriptors.
323
324
325Complete Practical Example
326^^^^^^^^^^^^^^^^^^^^^^^^^^
327
328In this example, we create a practical and powerful tool for locating
329notoriously hard to find data corruption bugs.
330
331
332Validator class
333---------------
334
335A validator is a descriptor for managed attribute access.  Prior to storing
336any data, it verifies that the new value meets various type and range
337restrictions.  If those restrictions aren't met, it raises an exception to
338prevent data corruption at its source.
339
340This :class:`Validator` class is both an :term:`abstract base class` and a
341managed attribute descriptor:
342
343.. testcode::
344
345    from abc import ABC, abstractmethod
346
347    class Validator(ABC):
348
349        def __set_name__(self, owner, name):
350            self.private_name = '_' + name
351
352        def __get__(self, obj, objtype=None):
353            return getattr(obj, self.private_name)
354
355        def __set__(self, obj, value):
356            self.validate(value)
357            setattr(obj, self.private_name, value)
358
359        @abstractmethod
360        def validate(self, value):
361            pass
362
363Custom validators need to inherit from :class:`Validator` and must supply a
364:meth:`validate` method to test various restrictions as needed.
365
366
367Custom validators
368-----------------
369
370Here are three practical data validation utilities:
371
3721) :class:`OneOf` verifies that a value is one of a restricted set of options.
373
3742) :class:`Number` verifies that a value is either an :class:`int` or
375   :class:`float`.  Optionally, it verifies that a value is between a given
376   minimum or maximum.
377
3783) :class:`String` verifies that a value is a :class:`str`.  Optionally, it
379   validates a given minimum or maximum length.  It can validate a
380   user-defined `predicate
381   <https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)>`_ as well.
382
383.. testcode::
384
385    class OneOf(Validator):
386
387        def __init__(self, *options):
388            self.options = set(options)
389
390        def validate(self, value):
391            if value not in self.options:
392                raise ValueError(f'Expected {value!r} to be one of {self.options!r}')
393
394    class Number(Validator):
395
396        def __init__(self, minvalue=None, maxvalue=None):
397            self.minvalue = minvalue
398            self.maxvalue = maxvalue
399
400        def validate(self, value):
401            if not isinstance(value, (int, float)):
402                raise TypeError(f'Expected {value!r} to be an int or float')
403            if self.minvalue is not None and value < self.minvalue:
404                raise ValueError(
405                    f'Expected {value!r} to be at least {self.minvalue!r}'
406                )
407            if self.maxvalue is not None and value > self.maxvalue:
408                raise ValueError(
409                    f'Expected {value!r} to be no more than {self.maxvalue!r}'
410                )
411
412    class String(Validator):
413
414        def __init__(self, minsize=None, maxsize=None, predicate=None):
415            self.minsize = minsize
416            self.maxsize = maxsize
417            self.predicate = predicate
418
419        def validate(self, value):
420            if not isinstance(value, str):
421                raise TypeError(f'Expected {value!r} to be an str')
422            if self.minsize is not None and len(value) < self.minsize:
423                raise ValueError(
424                    f'Expected {value!r} to be no smaller than {self.minsize!r}'
425                )
426            if self.maxsize is not None and len(value) > self.maxsize:
427                raise ValueError(
428                    f'Expected {value!r} to be no bigger than {self.maxsize!r}'
429                )
430            if self.predicate is not None and not self.predicate(value):
431                raise ValueError(
432                    f'Expected {self.predicate} to be true for {value!r}'
433                )
434
435
436Practical application
437---------------------
438
439Here's how the data validators can be used in a real class:
440
441.. testcode::
442
443    class Component:
444
445        name = String(minsize=3, maxsize=10, predicate=str.isupper)
446        kind = OneOf('wood', 'metal', 'plastic')
447        quantity = Number(minvalue=0)
448
449        def __init__(self, name, kind, quantity):
450            self.name = name
451            self.kind = kind
452            self.quantity = quantity
453
454The descriptors prevent invalid instances from being created:
455
456.. doctest::
457
458    >>> Component('Widget', 'metal', 5)      # Blocked: 'Widget' is not all uppercase
459    Traceback (most recent call last):
460        ...
461    ValueError: Expected <method 'isupper' of 'str' objects> to be true for 'Widget'
462
463    >>> Component('WIDGET', 'metle', 5)      # Blocked: 'metle' is misspelled
464    Traceback (most recent call last):
465        ...
466    ValueError: Expected 'metle' to be one of {'metal', 'plastic', 'wood'}
467
468    >>> Component('WIDGET', 'metal', -5)     # Blocked: -5 is negative
469    Traceback (most recent call last):
470        ...
471    ValueError: Expected -5 to be at least 0
472    >>> Component('WIDGET', 'metal', 'V')    # Blocked: 'V' isn't a number
473    Traceback (most recent call last):
474        ...
475    TypeError: Expected 'V' to be an int or float
476
477    >>> c = Component('WIDGET', 'metal', 5)  # Allowed:  The inputs are valid
478
479
480Technical Tutorial
481^^^^^^^^^^^^^^^^^^
482
483What follows is a more technical tutorial for the mechanics and details of how
484descriptors work.
485
486
487Abstract
488--------
489
490Defines descriptors, summarizes the protocol, and shows how descriptors are
491called.  Provides an example showing how object relational mappings work.
492
493Learning about descriptors not only provides access to a larger toolset, it
494creates a deeper understanding of how Python works.
495
496
497Definition and introduction
498---------------------------
499
500In general, a descriptor is an attribute value that has one of the methods in
501the descriptor protocol.  Those methods are :meth:`__get__`, :meth:`__set__`,
502and :meth:`__delete__`.  If any of those methods are defined for an
503attribute, it is said to be a :term:`descriptor`.
504
505The default behavior for attribute access is to get, set, or delete the
506attribute from an object's dictionary.  For instance, ``a.x`` has a lookup chain
507starting with ``a.__dict__['x']``, then ``type(a).__dict__['x']``, and
508continuing through the method resolution order of ``type(a)``. If the
509looked-up value is an object defining one of the descriptor methods, then Python
510may override the default behavior and invoke the descriptor method instead.
511Where this occurs in the precedence chain depends on which descriptor methods
512were defined.
513
514Descriptors are a powerful, general purpose protocol.  They are the mechanism
515behind properties, methods, static methods, class methods, and
516:func:`super()`.  They are used throughout Python itself.  Descriptors
517simplify the underlying C code and offer a flexible set of new tools for
518everyday Python programs.
519
520
521Descriptor protocol
522-------------------
523
524``descr.__get__(self, obj, type=None) -> value``
525
526``descr.__set__(self, obj, value) -> None``
527
528``descr.__delete__(self, obj) -> None``
529
530That is all there is to it.  Define any of these methods and an object is
531considered a descriptor and can override default behavior upon being looked up
532as an attribute.
533
534If an object defines :meth:`__set__` or :meth:`__delete__`, it is considered
535a data descriptor.  Descriptors that only define :meth:`__get__` are called
536non-data descriptors (they are often used for methods but other uses are
537possible).
538
539Data and non-data descriptors differ in how overrides are calculated with
540respect to entries in an instance's dictionary.  If an instance's dictionary
541has an entry with the same name as a data descriptor, the data descriptor
542takes precedence.  If an instance's dictionary has an entry with the same
543name as a non-data descriptor, the dictionary entry takes precedence.
544
545To make a read-only data descriptor, define both :meth:`__get__` and
546:meth:`__set__` with the :meth:`__set__` raising an :exc:`AttributeError` when
547called.  Defining the :meth:`__set__` method with an exception raising
548placeholder is enough to make it a data descriptor.
549
550
551Overview of descriptor invocation
552---------------------------------
553
554A descriptor can be called directly with ``desc.__get__(obj)`` or
555``desc.__get__(None, cls)``.
556
557But it is more common for a descriptor to be invoked automatically from
558attribute access.
559
560The expression ``obj.x`` looks up the attribute ``x`` in the chain of
561namespaces for ``obj``.  If the search finds a descriptor outside of the
562instance ``__dict__``, its :meth:`__get__` method is invoked according to the
563precedence rules listed below.
564
565The details of invocation depend on whether ``obj`` is an object, class, or
566instance of super.
567
568
569Invocation from an instance
570---------------------------
571
572Instance lookup scans through a chain of namespaces giving data descriptors
573the highest priority, followed by instance variables, then non-data
574descriptors, then class variables, and lastly :meth:`__getattr__` if it is
575provided.
576
577If a descriptor is found for ``a.x``, then it is invoked with:
578``desc.__get__(a, type(a))``.
579
580The logic for a dotted lookup is in :meth:`object.__getattribute__`.  Here is
581a pure Python equivalent:
582
583.. testcode::
584
585    def find_name_in_mro(cls, name, default):
586        "Emulate _PyType_Lookup() in Objects/typeobject.c"
587        for base in cls.__mro__:
588            if name in vars(base):
589                return vars(base)[name]
590        return default
591
592    def object_getattribute(obj, name):
593        "Emulate PyObject_GenericGetAttr() in Objects/object.c"
594        null = object()
595        objtype = type(obj)
596        cls_var = find_name_in_mro(objtype, name, null)
597        descr_get = getattr(type(cls_var), '__get__', null)
598        if descr_get is not null:
599            if (hasattr(type(cls_var), '__set__')
600                or hasattr(type(cls_var), '__delete__')):
601                return descr_get(cls_var, obj, objtype)     # data descriptor
602        if hasattr(obj, '__dict__') and name in vars(obj):
603            return vars(obj)[name]                          # instance variable
604        if descr_get is not null:
605            return descr_get(cls_var, obj, objtype)         # non-data descriptor
606        if cls_var is not null:
607            return cls_var                                  # class variable
608        raise AttributeError(name)
609
610
611.. testcode::
612    :hide:
613
614    # Test the fidelity of object_getattribute() by comparing it with the
615    # normal object.__getattribute__().  The former will be accessed by
616    # square brackets and the latter by the dot operator.
617
618    class Object:
619
620        def __getitem__(obj, name):
621            try:
622                return object_getattribute(obj, name)
623            except AttributeError:
624                if not hasattr(type(obj), '__getattr__'):
625                    raise
626            return type(obj).__getattr__(obj, name)             # __getattr__
627
628    class DualOperator(Object):
629
630        x = 10
631
632        def __init__(self, z):
633            self.z = z
634
635        @property
636        def p2(self):
637            return 2 * self.x
638
639        @property
640        def p3(self):
641            return 3 * self.x
642
643        def m5(self, y):
644            return 5 * y
645
646        def m7(self, y):
647            return 7 * y
648
649        def __getattr__(self, name):
650            return ('getattr_hook', self, name)
651
652    class DualOperatorWithSlots:
653
654        __getitem__ = Object.__getitem__
655
656        __slots__ = ['z']
657
658        x = 15
659
660        def __init__(self, z):
661            self.z = z
662
663        @property
664        def p2(self):
665            return 2 * self.x
666
667        def m5(self, y):
668            return 5 * y
669
670        def __getattr__(self, name):
671            return ('getattr_hook', self, name)
672
673    class D1:
674        def __get__(self, obj, objtype=None):
675            return type(self), obj, objtype
676
677    class U1:
678        x = D1()
679
680    class U2(U1):
681        pass
682
683.. doctest::
684    :hide:
685
686    >>> a = DualOperator(11)
687    >>> vars(a).update(p3 = '_p3', m7 = '_m7')
688    >>> a.x == a['x'] == 10
689    True
690    >>> a.z == a['z'] == 11
691    True
692    >>> a.p2 == a['p2'] == 20
693    True
694    >>> a.p3 == a['p3'] == 30
695    True
696    >>> a.m5(100) == a.m5(100) == 500
697    True
698    >>> a.m7 == a['m7'] == '_m7'
699    True
700    >>> a.g == a['g'] == ('getattr_hook', a, 'g')
701    True
702
703    >>> b = DualOperatorWithSlots(22)
704    >>> b.x == b['x'] == 15
705    True
706    >>> b.z == b['z'] == 22
707    True
708    >>> b.p2 == b['p2'] == 30
709    True
710    >>> b.m5(200) == b['m5'](200) == 1000
711    True
712    >>> b.g == b['g'] == ('getattr_hook', b, 'g')
713    True
714
715    >>> u2 = U2()
716    >>> object_getattribute(u2, 'x') == u2.x == (D1, u2, U2)
717    True
718
719Note, there is no :meth:`__getattr__` hook in the :meth:`__getattribute__`
720code.  That is why calling :meth:`__getattribute__` directly or with
721``super().__getattribute__`` will bypass :meth:`__getattr__` entirely.
722
723Instead, it is the dot operator and the :func:`getattr` function that are
724responsible for invoking :meth:`__getattr__` whenever :meth:`__getattribute__`
725raises an :exc:`AttributeError`.  Their logic is encapsulated in a helper
726function:
727
728.. testcode::
729
730    def getattr_hook(obj, name):
731        "Emulate slot_tp_getattr_hook() in Objects/typeobject.c"
732        try:
733            return obj.__getattribute__(name)
734        except AttributeError:
735            if not hasattr(type(obj), '__getattr__'):
736                raise
737        return type(obj).__getattr__(obj, name)             # __getattr__
738
739.. doctest::
740    :hide:
741
742
743    >>> class ClassWithGetAttr:
744    ...     x = 123
745    ...     def __getattr__(self, attr):
746    ...         return attr.upper()
747    ...
748    >>> cw = ClassWithGetAttr()
749    >>> cw.y = 456
750    >>> getattr_hook(cw, 'x')
751    123
752    >>> getattr_hook(cw, 'y')
753    456
754    >>> getattr_hook(cw, 'z')
755    'Z'
756
757    >>> class ClassWithoutGetAttr:
758    ...     x = 123
759    ...
760    >>> cwo = ClassWithoutGetAttr()
761    >>> cwo.y = 456
762    >>> getattr_hook(cwo, 'x')
763    123
764    >>> getattr_hook(cwo, 'y')
765    456
766    >>> getattr_hook(cwo, 'z')
767    Traceback (most recent call last):
768        ...
769    AttributeError: 'ClassWithoutGetAttr' object has no attribute 'z'
770
771
772Invocation from a class
773-----------------------
774
775The logic for a dotted lookup such as ``A.x`` is in
776:meth:`type.__getattribute__`.  The steps are similar to those for
777:meth:`object.__getattribute__` but the instance dictionary lookup is replaced
778by a search through the class's :term:`method resolution order`.
779
780If a descriptor is found, it is invoked with ``desc.__get__(None, A)``.
781
782The full C implementation can be found in :c:func:`type_getattro()` and
783:c:func:`_PyType_Lookup()` in :source:`Objects/typeobject.c`.
784
785
786Invocation from super
787---------------------
788
789The logic for super's dotted lookup is in the :meth:`__getattribute__` method for
790object returned by :class:`super()`.
791
792A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__``
793for the base class ``B`` immediately following ``A`` and then returns
794``B.__dict__['m'].__get__(obj, A)``.  If not a descriptor, ``m`` is returned
795unchanged.
796
797The full C implementation can be found in :c:func:`super_getattro()` in
798:source:`Objects/typeobject.c`.  A pure Python equivalent can be found in
799`Guido's Tutorial
800<https://www.python.org/download/releases/2.2.3/descrintro/#cooperation>`_.
801
802
803Summary of invocation logic
804---------------------------
805
806The mechanism for descriptors is embedded in the :meth:`__getattribute__()`
807methods for :class:`object`, :class:`type`, and :func:`super`.
808
809The important points to remember are:
810
811* Descriptors are invoked by the :meth:`__getattribute__` method.
812
813* Classes inherit this machinery from :class:`object`, :class:`type`, or
814  :func:`super`.
815
816* Overriding :meth:`__getattribute__` prevents automatic descriptor calls
817  because all the descriptor logic is in that method.
818
819* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make
820  different calls to :meth:`__get__`.  The first includes the instance and may
821  include the class.  The second puts in ``None`` for the instance and always
822  includes the class.
823
824* Data descriptors always override instance dictionaries.
825
826* Non-data descriptors may be overridden by instance dictionaries.
827
828
829Automatic name notification
830---------------------------
831
832Sometimes it is desirable for a descriptor to know what class variable name it
833was assigned to.  When a new class is created, the :class:`type` metaclass
834scans the dictionary of the new class.  If any of the entries are descriptors
835and if they define :meth:`__set_name__`, that method is called with two
836arguments.  The *owner* is the class where the descriptor is used, and the
837*name* is the class variable the descriptor was assigned to.
838
839The implementation details are in :c:func:`type_new()` and
840:c:func:`set_names()` in :source:`Objects/typeobject.c`.
841
842Since the update logic is in :meth:`type.__new__`, notifications only take
843place at the time of class creation.  If descriptors are added to the class
844afterwards, :meth:`__set_name__` will need to be called manually.
845
846
847ORM example
848-----------
849
850The following code is a simplified skeleton showing how data descriptors could
851be used to implement an `object relational mapping
852<https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping>`_.
853
854The essential idea is that the data is stored in an external database.  The
855Python instances only hold keys to the database's tables.  Descriptors take
856care of lookups or updates:
857
858.. testcode::
859
860    class Field:
861
862        def __set_name__(self, owner, name):
863            self.fetch = f'SELECT {name} FROM {owner.table} WHERE {owner.key}=?;'
864            self.store = f'UPDATE {owner.table} SET {name}=? WHERE {owner.key}=?;'
865
866        def __get__(self, obj, objtype=None):
867            return conn.execute(self.fetch, [obj.key]).fetchone()[0]
868
869        def __set__(self, obj, value):
870            conn.execute(self.store, [value, obj.key])
871            conn.commit()
872
873We can use the :class:`Field` class to define `models
874<https://en.wikipedia.org/wiki/Database_model>`_ that describe the schema for
875each table in a database:
876
877.. testcode::
878
879    class Movie:
880        table = 'Movies'                    # Table name
881        key = 'title'                       # Primary key
882        director = Field()
883        year = Field()
884
885        def __init__(self, key):
886            self.key = key
887
888    class Song:
889        table = 'Music'
890        key = 'title'
891        artist = Field()
892        year = Field()
893        genre = Field()
894
895        def __init__(self, key):
896            self.key = key
897
898To use the models, first connect to the database::
899
900    >>> import sqlite3
901    >>> conn = sqlite3.connect('entertainment.db')
902
903An interactive session shows how data is retrieved from the database and how
904it can be updated:
905
906.. testsetup::
907
908    song_data = [
909        ('Country Roads', 'John Denver', 1972),
910        ('Me and Bobby McGee', 'Janice Joplin', 1971),
911        ('Coal Miners Daughter', 'Loretta Lynn', 1970),
912    ]
913
914    movie_data = [
915        ('Star Wars', 'George Lucas', 1977),
916        ('Jaws', 'Steven Spielberg', 1975),
917        ('Aliens', 'James Cameron', 1986),
918    ]
919
920    import sqlite3
921
922    conn = sqlite3.connect(':memory:')
923    conn.execute('CREATE TABLE Music (title text, artist text, year integer);')
924    conn.execute('CREATE INDEX MusicNdx ON Music (title);')
925    conn.executemany('INSERT INTO Music VALUES (?, ?, ?);', song_data)
926    conn.execute('CREATE TABLE Movies (title text, director text, year integer);')
927    conn.execute('CREATE INDEX MovieNdx ON Music (title);')
928    conn.executemany('INSERT INTO Movies VALUES (?, ?, ?);', movie_data)
929    conn.commit()
930
931.. doctest::
932
933    >>> Movie('Star Wars').director
934    'George Lucas'
935    >>> jaws = Movie('Jaws')
936    >>> f'Released in {jaws.year} by {jaws.director}'
937    'Released in 1975 by Steven Spielberg'
938
939    >>> Song('Country Roads').artist
940    'John Denver'
941
942    >>> Movie('Star Wars').director = 'J.J. Abrams'
943    >>> Movie('Star Wars').director
944    'J.J. Abrams'
945
946
947Pure Python Equivalents
948^^^^^^^^^^^^^^^^^^^^^^^
949
950The descriptor protocol is simple and offers exciting possibilities.  Several
951use cases are so common that they have been prepackaged into built-in tools.
952Properties, bound methods, static methods, class methods, and \_\_slots\_\_ are
953all based on the descriptor protocol.
954
955
956Properties
957----------
958
959Calling :func:`property` is a succinct way of building a data descriptor that
960triggers a function call upon access to an attribute.  Its signature is::
961
962    property(fget=None, fset=None, fdel=None, doc=None) -> property
963
964The documentation shows a typical use to define a managed attribute ``x``:
965
966.. testcode::
967
968    class C:
969        def getx(self): return self.__x
970        def setx(self, value): self.__x = value
971        def delx(self): del self.__x
972        x = property(getx, setx, delx, "I'm the 'x' property.")
973
974.. doctest::
975    :hide:
976
977    >>> C.x.__doc__
978    "I'm the 'x' property."
979    >>> c.x = 2.71828
980    >>> c.x
981    2.71828
982    >>> del c.x
983    >>> c.x
984    Traceback (most recent call last):
985      ...
986    AttributeError: 'C' object has no attribute '_C__x'
987
988To see how :func:`property` is implemented in terms of the descriptor protocol,
989here is a pure Python equivalent:
990
991.. testcode::
992
993    class Property:
994        "Emulate PyProperty_Type() in Objects/descrobject.c"
995
996        def __init__(self, fget=None, fset=None, fdel=None, doc=None):
997            self.fget = fget
998            self.fset = fset
999            self.fdel = fdel
1000            if doc is None and fget is not None:
1001                doc = fget.__doc__
1002            self.__doc__ = doc
1003            self._name = ''
1004
1005        def __set_name__(self, owner, name):
1006            self._name = name
1007
1008        def __get__(self, obj, objtype=None):
1009            if obj is None:
1010                return self
1011            if self.fget is None:
1012                raise AttributeError(f"property '{self._name}' has no getter")
1013            return self.fget(obj)
1014
1015        def __set__(self, obj, value):
1016            if self.fset is None:
1017                raise AttributeError(f"property '{self._name}' has no setter")
1018            self.fset(obj, value)
1019
1020        def __delete__(self, obj):
1021            if self.fdel is None:
1022                raise AttributeError(f"property '{self._name}' has no deleter")
1023            self.fdel(obj)
1024
1025        def getter(self, fget):
1026            prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
1027            prop._name = self._name
1028            return prop
1029
1030        def setter(self, fset):
1031            prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
1032            prop._name = self._name
1033            return prop
1034
1035        def deleter(self, fdel):
1036            prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
1037            prop._name = self._name
1038            return prop
1039
1040.. testcode::
1041    :hide:
1042
1043    # Verify the Property() emulation
1044
1045    class CC:
1046        def getx(self):
1047            return self.__x
1048        def setx(self, value):
1049            self.__x = value
1050        def delx(self):
1051            del self.__x
1052        x = Property(getx, setx, delx, "I'm the 'x' property.")
1053
1054    # Now do it again but use the decorator style
1055
1056    class CCC:
1057        @Property
1058        def x(self):
1059            return self.__x
1060        @x.setter
1061        def x(self, value):
1062            self.__x = value
1063        @x.deleter
1064        def x(self):
1065            del self.__x
1066
1067
1068.. doctest::
1069    :hide:
1070
1071    >>> cc = CC()
1072    >>> hasattr(cc, 'x')
1073    False
1074    >>> cc.x = 33
1075    >>> cc.x
1076    33
1077    >>> del cc.x
1078    >>> hasattr(cc, 'x')
1079    False
1080
1081    >>> ccc = CCC()
1082    >>> hasattr(ccc, 'x')
1083    False
1084    >>> ccc.x = 333
1085    >>> ccc.x == 333
1086    True
1087    >>> del ccc.x
1088    >>> hasattr(ccc, 'x')
1089    False
1090
1091The :func:`property` builtin helps whenever a user interface has granted
1092attribute access and then subsequent changes require the intervention of a
1093method.
1094
1095For instance, a spreadsheet class may grant access to a cell value through
1096``Cell('b10').value``. Subsequent improvements to the program require the cell
1097to be recalculated on every access; however, the programmer does not want to
1098affect existing client code accessing the attribute directly.  The solution is
1099to wrap access to the value attribute in a property data descriptor:
1100
1101.. testcode::
1102
1103    class Cell:
1104        ...
1105
1106        @property
1107        def value(self):
1108            "Recalculate the cell before returning value"
1109            self.recalc()
1110            return self._value
1111
1112Either the built-in :func:`property` or our :func:`Property` equivalent would
1113work in this example.
1114
1115
1116Functions and methods
1117---------------------
1118
1119Python's object oriented features are built upon a function based environment.
1120Using non-data descriptors, the two are merged seamlessly.
1121
1122Functions stored in class dictionaries get turned into methods when invoked.
1123Methods only differ from regular functions in that the object instance is
1124prepended to the other arguments.  By convention, the instance is called
1125*self* but could be called *this* or any other variable name.
1126
1127Methods can be created manually with :class:`types.MethodType` which is
1128roughly equivalent to:
1129
1130.. testcode::
1131
1132    class MethodType:
1133        "Emulate PyMethod_Type in Objects/classobject.c"
1134
1135        def __init__(self, func, obj):
1136            self.__func__ = func
1137            self.__self__ = obj
1138
1139        def __call__(self, *args, **kwargs):
1140            func = self.__func__
1141            obj = self.__self__
1142            return func(obj, *args, **kwargs)
1143
1144To support automatic creation of methods, functions include the
1145:meth:`__get__` method for binding methods during attribute access.  This
1146means that functions are non-data descriptors that return bound methods
1147during dotted lookup from an instance.  Here's how it works:
1148
1149.. testcode::
1150
1151    class Function:
1152        ...
1153
1154        def __get__(self, obj, objtype=None):
1155            "Simulate func_descr_get() in Objects/funcobject.c"
1156            if obj is None:
1157                return self
1158            return MethodType(self, obj)
1159
1160Running the following class in the interpreter shows how the function
1161descriptor works in practice:
1162
1163.. testcode::
1164
1165    class D:
1166        def f(self, x):
1167             return x
1168
1169The function has a :term:`qualified name` attribute to support introspection:
1170
1171.. doctest::
1172
1173    >>> D.f.__qualname__
1174    'D.f'
1175
1176Accessing the function through the class dictionary does not invoke
1177:meth:`__get__`.  Instead, it just returns the underlying function object::
1178
1179    >>> D.__dict__['f']
1180    <function D.f at 0x00C45070>
1181
1182Dotted access from a class calls :meth:`__get__` which just returns the
1183underlying function unchanged::
1184
1185    >>> D.f
1186    <function D.f at 0x00C45070>
1187
1188The interesting behavior occurs during dotted access from an instance.  The
1189dotted lookup calls :meth:`__get__` which returns a bound method object::
1190
1191    >>> d = D()
1192    >>> d.f
1193    <bound method D.f of <__main__.D object at 0x00B18C90>>
1194
1195Internally, the bound method stores the underlying function and the bound
1196instance::
1197
1198    >>> d.f.__func__
1199    <function D.f at 0x00C45070>
1200
1201    >>> d.f.__self__
1202    <__main__.D object at 0x1012e1f98>
1203
1204If you have ever wondered where *self* comes from in regular methods or where
1205*cls* comes from in class methods, this is it!
1206
1207
1208Kinds of methods
1209----------------
1210
1211Non-data descriptors provide a simple mechanism for variations on the usual
1212patterns of binding functions into methods.
1213
1214To recap, functions have a :meth:`__get__` method so that they can be converted
1215to a method when accessed as attributes.  The non-data descriptor transforms an
1216``obj.f(*args)`` call into ``f(obj, *args)``.  Calling ``cls.f(*args)``
1217becomes ``f(*args)``.
1218
1219This chart summarizes the binding and its two most useful variants:
1220
1221      +-----------------+----------------------+------------------+
1222      | Transformation  | Called from an       | Called from a    |
1223      |                 | object               | class            |
1224      +=================+======================+==================+
1225      | function        | f(obj, \*args)       | f(\*args)        |
1226      +-----------------+----------------------+------------------+
1227      | staticmethod    | f(\*args)            | f(\*args)        |
1228      +-----------------+----------------------+------------------+
1229      | classmethod     | f(type(obj), \*args) | f(cls, \*args)   |
1230      +-----------------+----------------------+------------------+
1231
1232
1233Static methods
1234--------------
1235
1236Static methods return the underlying function without changes.  Calling either
1237``c.f`` or ``C.f`` is the equivalent of a direct lookup into
1238``object.__getattribute__(c, "f")`` or ``object.__getattribute__(C, "f")``. As a
1239result, the function becomes identically accessible from either an object or a
1240class.
1241
1242Good candidates for static methods are methods that do not reference the
1243``self`` variable.
1244
1245For instance, a statistics package may include a container class for
1246experimental data.  The class provides normal methods for computing the average,
1247mean, median, and other descriptive statistics that depend on the data. However,
1248there may be useful functions which are conceptually related but do not depend
1249on the data.  For instance, ``erf(x)`` is handy conversion routine that comes up
1250in statistical work but does not directly depend on a particular dataset.
1251It can be called either from an object or the class:  ``s.erf(1.5) --> .9332`` or
1252``Sample.erf(1.5) --> .9332``.
1253
1254Since static methods return the underlying function with no changes, the
1255example calls are unexciting:
1256
1257.. testcode::
1258
1259    class E:
1260        @staticmethod
1261        def f(x):
1262            return x * 10
1263
1264.. doctest::
1265
1266    >>> E.f(3)
1267    30
1268    >>> E().f(3)
1269    30
1270
1271Using the non-data descriptor protocol, a pure Python version of
1272:func:`staticmethod` would look like this:
1273
1274.. testcode::
1275
1276    import functools
1277
1278    class StaticMethod:
1279        "Emulate PyStaticMethod_Type() in Objects/funcobject.c"
1280
1281        def __init__(self, f):
1282            self.f = f
1283            functools.update_wrapper(self, f)
1284
1285        def __get__(self, obj, objtype=None):
1286            return self.f
1287
1288        def __call__(self, *args, **kwds):
1289            return self.f(*args, **kwds)
1290
1291The :func:`functools.update_wrapper` call adds a ``__wrapped__`` attribute
1292that refers to the underlying function.  Also it carries forward
1293the attributes necessary to make the wrapper look like the wrapped
1294function: ``__name__``, ``__qualname__``, ``__doc__``, and ``__annotations__``.
1295
1296.. testcode::
1297    :hide:
1298
1299    class E_sim:
1300        @StaticMethod
1301        def f(x: int) -> str:
1302            "Simple function example"
1303            return "!" * x
1304
1305    wrapped_ord = StaticMethod(ord)
1306
1307.. doctest::
1308    :hide:
1309
1310    >>> E_sim.f(3)
1311    '!!!'
1312    >>> E_sim().f(3)
1313    '!!!'
1314
1315    >>> sm = vars(E_sim)['f']
1316    >>> type(sm).__name__
1317    'StaticMethod'
1318    >>> f = E_sim.f
1319    >>> type(f).__name__
1320    'function'
1321    >>> sm.__name__
1322    'f'
1323    >>> f.__name__
1324    'f'
1325    >>> sm.__qualname__
1326    'E_sim.f'
1327    >>> f.__qualname__
1328    'E_sim.f'
1329    >>> sm.__doc__
1330    'Simple function example'
1331    >>> f.__doc__
1332    'Simple function example'
1333    >>> sm.__annotations__
1334    {'x': <class 'int'>, 'return': <class 'str'>}
1335    >>> f.__annotations__
1336    {'x': <class 'int'>, 'return': <class 'str'>}
1337    >>> sm.__module__ == f.__module__
1338    True
1339    >>> sm(3)
1340    '!!!'
1341    >>> f(3)
1342    '!!!'
1343
1344    >>> wrapped_ord('A')
1345    65
1346    >>> wrapped_ord.__module__ == ord.__module__
1347    True
1348    >>> wrapped_ord.__wrapped__ == ord
1349    True
1350    >>> wrapped_ord.__name__ == ord.__name__
1351    True
1352    >>> wrapped_ord.__qualname__ == ord.__qualname__
1353    True
1354    >>> wrapped_ord.__doc__ == ord.__doc__
1355    True
1356
1357
1358Class methods
1359-------------
1360
1361Unlike static methods, class methods prepend the class reference to the
1362argument list before calling the function.  This format is the same
1363for whether the caller is an object or a class:
1364
1365.. testcode::
1366
1367    class F:
1368        @classmethod
1369        def f(cls, x):
1370            return cls.__name__, x
1371
1372.. doctest::
1373
1374    >>> F.f(3)
1375    ('F', 3)
1376    >>> F().f(3)
1377    ('F', 3)
1378
1379This behavior is useful whenever the method only needs to have a class
1380reference and does not rely on data stored in a specific instance.  One use for
1381class methods is to create alternate class constructors.  For example, the
1382classmethod :func:`dict.fromkeys` creates a new dictionary from a list of
1383keys.  The pure Python equivalent is:
1384
1385.. testcode::
1386
1387    class Dict(dict):
1388        @classmethod
1389        def fromkeys(cls, iterable, value=None):
1390            "Emulate dict_fromkeys() in Objects/dictobject.c"
1391            d = cls()
1392            for key in iterable:
1393                d[key] = value
1394            return d
1395
1396Now a new dictionary of unique keys can be constructed like this:
1397
1398.. doctest::
1399
1400    >>> d = Dict.fromkeys('abracadabra')
1401    >>> type(d) is Dict
1402    True
1403    >>> d
1404    {'a': None, 'b': None, 'r': None, 'c': None, 'd': None}
1405
1406Using the non-data descriptor protocol, a pure Python version of
1407:func:`classmethod` would look like this:
1408
1409.. testcode::
1410
1411    import functools
1412
1413    class ClassMethod:
1414        "Emulate PyClassMethod_Type() in Objects/funcobject.c"
1415
1416        def __init__(self, f):
1417            self.f = f
1418            functools.update_wrapper(self, f)
1419
1420        def __get__(self, obj, cls=None):
1421            if cls is None:
1422                cls = type(obj)
1423            if hasattr(type(self.f), '__get__'):
1424                # This code path was added in Python 3.9
1425                # and was deprecated in Python 3.11.
1426                return self.f.__get__(cls, cls)
1427            return MethodType(self.f, cls)
1428
1429.. testcode::
1430    :hide:
1431
1432    # Verify the emulation works
1433    class T:
1434        @ClassMethod
1435        def cm(cls, x: int, y: str) -> tuple[str, int, str]:
1436            "Class method that returns a tuple"
1437            return (cls.__name__, x, y)
1438
1439        @ClassMethod
1440        @property
1441        def __doc__(cls):
1442            return f'A doc for {cls.__name__!r}'
1443
1444
1445.. doctest::
1446    :hide:
1447
1448    >>> T.cm(11, 22)
1449    ('T', 11, 22)
1450
1451    # Also call it from an instance
1452    >>> t = T()
1453    >>> t.cm(11, 22)
1454    ('T', 11, 22)
1455
1456    # Check the alternate path for chained descriptors
1457    >>> T.__doc__
1458    "A doc for 'T'"
1459
1460    # Verify that T uses our emulation
1461    >>> type(vars(T)['cm']).__name__
1462    'ClassMethod'
1463
1464    # Verify that update_wrapper() correctly copied attributes
1465    >>> T.cm.__name__
1466    'cm'
1467    >>> T.cm.__qualname__
1468    'T.cm'
1469    >>> T.cm.__doc__
1470    'Class method that returns a tuple'
1471    >>> T.cm.__annotations__
1472    {'x': <class 'int'>, 'y': <class 'str'>, 'return': tuple[str, int, str]}
1473
1474    # Verify that __wrapped__ was added and works correctly
1475    >>> f = vars(T)['cm'].__wrapped__
1476    >>> type(f).__name__
1477    'function'
1478    >>> f.__name__
1479    'cm'
1480    >>> f(T, 11, 22)
1481    ('T', 11, 22)
1482
1483
1484The code path for ``hasattr(type(self.f), '__get__')`` was added in
1485Python 3.9 and makes it possible for :func:`classmethod` to support
1486chained decorators.  For example, a classmethod and property could be
1487chained together.  In Python 3.11, this functionality was deprecated.
1488
1489.. testcode::
1490
1491    class G:
1492        @classmethod
1493        @property
1494        def __doc__(cls):
1495            return f'A doc for {cls.__name__!r}'
1496
1497.. doctest::
1498
1499    >>> G.__doc__
1500    "A doc for 'G'"
1501
1502The :func:`functools.update_wrapper` call in ``ClassMethod`` adds a
1503``__wrapped__`` attribute that refers to the underlying function.  Also
1504it carries forward the attributes necessary to make the wrapper look
1505like the wrapped function: ``__name__``, ``__qualname__``, ``__doc__``,
1506and ``__annotations__``.
1507
1508
1509Member objects and __slots__
1510----------------------------
1511
1512When a class defines ``__slots__``, it replaces instance dictionaries with a
1513fixed-length array of slot values.  From a user point of view that has
1514several effects:
1515
15161. Provides immediate detection of bugs due to misspelled attribute
1517assignments.  Only attribute names specified in ``__slots__`` are allowed:
1518
1519.. testcode::
1520
1521        class Vehicle:
1522            __slots__ = ('id_number', 'make', 'model')
1523
1524.. doctest::
1525
1526        >>> auto = Vehicle()
1527        >>> auto.id_nubmer = 'VYE483814LQEX'
1528        Traceback (most recent call last):
1529            ...
1530        AttributeError: 'Vehicle' object has no attribute 'id_nubmer'
1531
15322. Helps create immutable objects where descriptors manage access to private
1533attributes stored in ``__slots__``:
1534
1535.. testcode::
1536
1537    class Immutable:
1538
1539        __slots__ = ('_dept', '_name')          # Replace the instance dictionary
1540
1541        def __init__(self, dept, name):
1542            self._dept = dept                   # Store to private attribute
1543            self._name = name                   # Store to private attribute
1544
1545        @property                               # Read-only descriptor
1546        def dept(self):
1547            return self._dept
1548
1549        @property
1550        def name(self):                         # Read-only descriptor
1551            return self._name
1552
1553.. doctest::
1554
1555    >>> mark = Immutable('Botany', 'Mark Watney')
1556    >>> mark.dept
1557    'Botany'
1558    >>> mark.dept = 'Space Pirate'
1559    Traceback (most recent call last):
1560        ...
1561    AttributeError: property 'dept' of 'Immutable' object has no setter
1562    >>> mark.location = 'Mars'
1563    Traceback (most recent call last):
1564        ...
1565    AttributeError: 'Immutable' object has no attribute 'location'
1566
15673. Saves memory.  On a 64-bit Linux build, an instance with two attributes
1568takes 48 bytes with ``__slots__`` and 152 bytes without.  This `flyweight
1569design pattern <https://en.wikipedia.org/wiki/Flyweight_pattern>`_ likely only
1570matters when a large number of instances are going to be created.
1571
15724. Improves speed.  Reading instance variables is 35% faster with
1573``__slots__`` (as measured with Python 3.10 on an Apple M1 processor).
1574
15755. Blocks tools like :func:`functools.cached_property` which require an
1576instance dictionary to function correctly:
1577
1578.. testcode::
1579
1580    from functools import cached_property
1581
1582    class CP:
1583        __slots__ = ()                          # Eliminates the instance dict
1584
1585        @cached_property                        # Requires an instance dict
1586        def pi(self):
1587            return 4 * sum((-1.0)**n / (2.0*n + 1.0)
1588                           for n in reversed(range(100_000)))
1589
1590.. doctest::
1591
1592    >>> CP().pi
1593    Traceback (most recent call last):
1594      ...
1595    TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property.
1596
1597It is not possible to create an exact drop-in pure Python version of
1598``__slots__`` because it requires direct access to C structures and control
1599over object memory allocation.  However, we can build a mostly faithful
1600simulation where the actual C structure for slots is emulated by a private
1601``_slotvalues`` list.  Reads and writes to that private structure are managed
1602by member descriptors:
1603
1604.. testcode::
1605
1606    null = object()
1607
1608    class Member:
1609
1610        def __init__(self, name, clsname, offset):
1611            'Emulate PyMemberDef in Include/structmember.h'
1612            # Also see descr_new() in Objects/descrobject.c
1613            self.name = name
1614            self.clsname = clsname
1615            self.offset = offset
1616
1617        def __get__(self, obj, objtype=None):
1618            'Emulate member_get() in Objects/descrobject.c'
1619            # Also see PyMember_GetOne() in Python/structmember.c
1620            if obj is None:
1621                return self
1622            value = obj._slotvalues[self.offset]
1623            if value is null:
1624                raise AttributeError(self.name)
1625            return value
1626
1627        def __set__(self, obj, value):
1628            'Emulate member_set() in Objects/descrobject.c'
1629            obj._slotvalues[self.offset] = value
1630
1631        def __delete__(self, obj):
1632            'Emulate member_delete() in Objects/descrobject.c'
1633            value = obj._slotvalues[self.offset]
1634            if value is null:
1635                raise AttributeError(self.name)
1636            obj._slotvalues[self.offset] = null
1637
1638        def __repr__(self):
1639            'Emulate member_repr() in Objects/descrobject.c'
1640            return f'<Member {self.name!r} of {self.clsname!r}>'
1641
1642The :meth:`type.__new__` method takes care of adding member objects to class
1643variables:
1644
1645.. testcode::
1646
1647    class Type(type):
1648        'Simulate how the type metaclass adds member objects for slots'
1649
1650        def __new__(mcls, clsname, bases, mapping, **kwargs):
1651            'Emulate type_new() in Objects/typeobject.c'
1652            # type_new() calls PyTypeReady() which calls add_methods()
1653            slot_names = mapping.get('slot_names', [])
1654            for offset, name in enumerate(slot_names):
1655                mapping[name] = Member(name, clsname, offset)
1656            return type.__new__(mcls, clsname, bases, mapping, **kwargs)
1657
1658The :meth:`object.__new__` method takes care of creating instances that have
1659slots instead of an instance dictionary.  Here is a rough simulation in pure
1660Python:
1661
1662.. testcode::
1663
1664    class Object:
1665        'Simulate how object.__new__() allocates memory for __slots__'
1666
1667        def __new__(cls, *args, **kwargs):
1668            'Emulate object_new() in Objects/typeobject.c'
1669            inst = super().__new__(cls)
1670            if hasattr(cls, 'slot_names'):
1671                empty_slots = [null] * len(cls.slot_names)
1672                object.__setattr__(inst, '_slotvalues', empty_slots)
1673            return inst
1674
1675        def __setattr__(self, name, value):
1676            'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1677            cls = type(self)
1678            if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1679                raise AttributeError(
1680                    f'{cls.__name__!r} object has no attribute {name!r}'
1681                )
1682            super().__setattr__(name, value)
1683
1684        def __delattr__(self, name):
1685            'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1686            cls = type(self)
1687            if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1688                raise AttributeError(
1689                    f'{cls.__name__!r} object has no attribute {name!r}'
1690                )
1691            super().__delattr__(name)
1692
1693To use the simulation in a real class, just inherit from :class:`Object` and
1694set the :term:`metaclass` to :class:`Type`:
1695
1696.. testcode::
1697
1698    class H(Object, metaclass=Type):
1699        'Instance variables stored in slots'
1700
1701        slot_names = ['x', 'y']
1702
1703        def __init__(self, x, y):
1704            self.x = x
1705            self.y = y
1706
1707At this point, the metaclass has loaded member objects for *x* and *y*::
1708
1709    >>> from pprint import pp
1710    >>> pp(dict(vars(H)))
1711    {'__module__': '__main__',
1712     '__doc__': 'Instance variables stored in slots',
1713     'slot_names': ['x', 'y'],
1714     '__init__': <function H.__init__ at 0x7fb5d302f9d0>,
1715     'x': <Member 'x' of 'H'>,
1716     'y': <Member 'y' of 'H'>}
1717
1718.. doctest::
1719    :hide:
1720
1721    # We test this separately because the preceding section is not
1722    # doctestable due to the hex memory address for the __init__ function
1723    >>> isinstance(vars(H)['x'], Member)
1724    True
1725    >>> isinstance(vars(H)['y'], Member)
1726    True
1727
1728When instances are created, they have a ``slot_values`` list where the
1729attributes are stored:
1730
1731.. doctest::
1732
1733    >>> h = H(10, 20)
1734    >>> vars(h)
1735    {'_slotvalues': [10, 20]}
1736    >>> h.x = 55
1737    >>> vars(h)
1738    {'_slotvalues': [55, 20]}
1739
1740Misspelled or unassigned attributes will raise an exception:
1741
1742.. doctest::
1743
1744    >>> h.xz
1745    Traceback (most recent call last):
1746        ...
1747    AttributeError: 'H' object has no attribute 'xz'
1748
1749.. doctest::
1750   :hide:
1751
1752    # Examples for deleted attributes are not shown because this section
1753    # is already a bit lengthy.  We still test that code here.
1754    >>> del h.x
1755    >>> hasattr(h, 'x')
1756    False
1757
1758    # Also test the code for uninitialized slots
1759    >>> class HU(Object, metaclass=Type):
1760    ...     slot_names = ['x', 'y']
1761    ...
1762    >>> hu = HU()
1763    >>> hasattr(hu, 'x')
1764    False
1765    >>> hasattr(hu, 'y')
1766    False
1767