• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 object_getattribute(obj, name):
586        "Emulate PyObject_GenericGetAttr() in Objects/object.c"
587        null = object()
588        objtype = type(obj)
589        cls_var = getattr(objtype, name, null)
590        descr_get = getattr(type(cls_var), '__get__', null)
591        if descr_get is not null:
592            if (hasattr(type(cls_var), '__set__')
593                or hasattr(type(cls_var), '__delete__')):
594                return descr_get(cls_var, obj, objtype)     # data descriptor
595        if hasattr(obj, '__dict__') and name in vars(obj):
596            return vars(obj)[name]                          # instance variable
597        if descr_get is not null:
598            return descr_get(cls_var, obj, objtype)         # non-data descriptor
599        if cls_var is not null:
600            return cls_var                                  # class variable
601        raise AttributeError(name)
602
603
604.. testcode::
605    :hide:
606
607    # Test the fidelity of object_getattribute() by comparing it with the
608    # normal object.__getattribute__().  The former will be accessed by
609    # square brackets and the latter by the dot operator.
610
611    class Object:
612
613        def __getitem__(obj, name):
614            try:
615                return object_getattribute(obj, name)
616            except AttributeError:
617                if not hasattr(type(obj), '__getattr__'):
618                    raise
619            return type(obj).__getattr__(obj, name)             # __getattr__
620
621    class DualOperator(Object):
622
623        x = 10
624
625        def __init__(self, z):
626            self.z = z
627
628        @property
629        def p2(self):
630            return 2 * self.x
631
632        @property
633        def p3(self):
634            return 3 * self.x
635
636        def m5(self, y):
637            return 5 * y
638
639        def m7(self, y):
640            return 7 * y
641
642        def __getattr__(self, name):
643            return ('getattr_hook', self, name)
644
645    class DualOperatorWithSlots:
646
647        __getitem__ = Object.__getitem__
648
649        __slots__ = ['z']
650
651        x = 15
652
653        def __init__(self, z):
654            self.z = z
655
656        @property
657        def p2(self):
658            return 2 * self.x
659
660        def m5(self, y):
661            return 5 * y
662
663        def __getattr__(self, name):
664            return ('getattr_hook', self, name)
665
666
667.. doctest::
668    :hide:
669
670    >>> a = DualOperator(11)
671    >>> vars(a).update(p3 = '_p3', m7 = '_m7')
672    >>> a.x == a['x'] == 10
673    True
674    >>> a.z == a['z'] == 11
675    True
676    >>> a.p2 == a['p2'] == 20
677    True
678    >>> a.p3 == a['p3'] == 30
679    True
680    >>> a.m5(100) == a.m5(100) == 500
681    True
682    >>> a.m7 == a['m7'] == '_m7'
683    True
684    >>> a.g == a['g'] == ('getattr_hook', a, 'g')
685    True
686
687    >>> b = DualOperatorWithSlots(22)
688    >>> b.x == b['x'] == 15
689    True
690    >>> b.z == b['z'] == 22
691    True
692    >>> b.p2 == b['p2'] == 30
693    True
694    >>> b.m5(200) == b['m5'](200) == 1000
695    True
696    >>> b.g == b['g'] == ('getattr_hook', b, 'g')
697    True
698
699
700Interestingly, attribute lookup doesn't call :meth:`object.__getattribute__`
701directly.  Instead, both the dot operator and the :func:`getattr` function
702perform attribute lookup by way of a helper function:
703
704.. testcode::
705
706    def getattr_hook(obj, name):
707        "Emulate slot_tp_getattr_hook() in Objects/typeobject.c"
708        try:
709            return obj.__getattribute__(name)
710        except AttributeError:
711            if not hasattr(type(obj), '__getattr__'):
712                raise
713        return type(obj).__getattr__(obj, name)             # __getattr__
714
715.. doctest::
716    :hide:
717
718
719    >>> class ClassWithGetAttr:
720    ...     x = 123
721    ...     def __getattr__(self, attr):
722    ...         return attr.upper()
723    ...
724    >>> cw = ClassWithGetAttr()
725    >>> cw.y = 456
726    >>> getattr_hook(cw, 'x')
727    123
728    >>> getattr_hook(cw, 'y')
729    456
730    >>> getattr_hook(cw, 'z')
731    'Z'
732
733    >>> class ClassWithoutGetAttr:
734    ...     x = 123
735    ...
736    >>> cwo = ClassWithoutGetAttr()
737    >>> cwo.y = 456
738    >>> getattr_hook(cwo, 'x')
739    123
740    >>> getattr_hook(cwo, 'y')
741    456
742    >>> getattr_hook(cwo, 'z')
743    Traceback (most recent call last):
744        ...
745    AttributeError: 'ClassWithoutGetAttr' object has no attribute 'z'
746
747So if :meth:`__getattr__` exists, it is called whenever :meth:`__getattribute__`
748raises :exc:`AttributeError` (either directly or in one of the descriptor calls).
749
750Also, if a user calls :meth:`object.__getattribute__` directly, the
751:meth:`__getattr__` hook is bypassed entirely.
752
753
754Invocation from a class
755-----------------------
756
757The logic for a dotted lookup such as ``A.x`` is in
758:meth:`type.__getattribute__`.  The steps are similar to those for
759:meth:`object.__getattribute__` but the instance dictionary lookup is replaced
760by a search through the class's :term:`method resolution order`.
761
762If a descriptor is found, it is invoked with ``desc.__get__(None, A)``.
763
764The full C implementation can be found in :c:func:`type_getattro()` and
765:c:func:`_PyType_Lookup()` in :source:`Objects/typeobject.c`.
766
767
768Invocation from super
769---------------------
770
771The logic for super's dotted lookup is in the :meth:`__getattribute__` method for
772object returned by :class:`super()`.
773
774A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__``
775for the base class ``B`` immediately following ``A`` and then returns
776``B.__dict__['m'].__get__(obj, A)``.  If not a descriptor, ``m`` is returned
777unchanged.
778
779The full C implementation can be found in :c:func:`super_getattro()` in
780:source:`Objects/typeobject.c`.  A pure Python equivalent can be found in
781`Guido's Tutorial
782<https://www.python.org/download/releases/2.2.3/descrintro/#cooperation>`_.
783
784
785Summary of invocation logic
786---------------------------
787
788The mechanism for descriptors is embedded in the :meth:`__getattribute__()`
789methods for :class:`object`, :class:`type`, and :func:`super`.
790
791The important points to remember are:
792
793* Descriptors are invoked by the :meth:`__getattribute__` method.
794
795* Classes inherit this machinery from :class:`object`, :class:`type`, or
796  :func:`super`.
797
798* Overriding :meth:`__getattribute__` prevents automatic descriptor calls
799  because all the descriptor logic is in that method.
800
801* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make
802  different calls to :meth:`__get__`.  The first includes the instance and may
803  include the class.  The second puts in ``None`` for the instance and always
804  includes the class.
805
806* Data descriptors always override instance dictionaries.
807
808* Non-data descriptors may be overridden by instance dictionaries.
809
810
811Automatic name notification
812---------------------------
813
814Sometimes it is desirable for a descriptor to know what class variable name it
815was assigned to.  When a new class is created, the :class:`type` metaclass
816scans the dictionary of the new class.  If any of the entries are descriptors
817and if they define :meth:`__set_name__`, that method is called with two
818arguments.  The *owner* is the class where the descriptor is used, and the
819*name* is the class variable the descriptor was assigned to.
820
821The implementation details are in :c:func:`type_new()` and
822:c:func:`set_names()` in :source:`Objects/typeobject.c`.
823
824Since the update logic is in :meth:`type.__new__`, notifications only take
825place at the time of class creation.  If descriptors are added to the class
826afterwards, :meth:`__set_name__` will need to be called manually.
827
828
829ORM example
830-----------
831
832The following code is simplified skeleton showing how data descriptors could
833be used to implement an `object relational mapping
834<https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping>`_.
835
836The essential idea is that the data is stored in an external database.  The
837Python instances only hold keys to the database's tables.  Descriptors take
838care of lookups or updates:
839
840.. testcode::
841
842    class Field:
843
844        def __set_name__(self, owner, name):
845            self.fetch = f'SELECT {name} FROM {owner.table} WHERE {owner.key}=?;'
846            self.store = f'UPDATE {owner.table} SET {name}=? WHERE {owner.key}=?;'
847
848        def __get__(self, obj, objtype=None):
849            return conn.execute(self.fetch, [obj.key]).fetchone()[0]
850
851        def __set__(self, obj, value):
852            conn.execute(self.store, [value, obj.key])
853            conn.commit()
854
855We can use the :class:`Field` class to define `models
856<https://en.wikipedia.org/wiki/Database_model>`_ that describe the schema for
857each table in a database:
858
859.. testcode::
860
861    class Movie:
862        table = 'Movies'                    # Table name
863        key = 'title'                       # Primary key
864        director = Field()
865        year = Field()
866
867        def __init__(self, key):
868            self.key = key
869
870    class Song:
871        table = 'Music'
872        key = 'title'
873        artist = Field()
874        year = Field()
875        genre = Field()
876
877        def __init__(self, key):
878            self.key = key
879
880To use the models, first connect to the database::
881
882    >>> import sqlite3
883    >>> conn = sqlite3.connect('entertainment.db')
884
885An interactive session shows how data is retrieved from the database and how
886it can be updated:
887
888.. testsetup::
889
890    song_data = [
891        ('Country Roads', 'John Denver', 1972),
892        ('Me and Bobby McGee', 'Janice Joplin', 1971),
893        ('Coal Miners Daughter', 'Loretta Lynn', 1970),
894    ]
895
896    movie_data = [
897        ('Star Wars', 'George Lucas', 1977),
898        ('Jaws', 'Steven Spielberg', 1975),
899        ('Aliens', 'James Cameron', 1986),
900    ]
901
902    import sqlite3
903
904    conn = sqlite3.connect(':memory:')
905    conn.execute('CREATE TABLE Music (title text, artist text, year integer);')
906    conn.execute('CREATE INDEX MusicNdx ON Music (title);')
907    conn.executemany('INSERT INTO Music VALUES (?, ?, ?);', song_data)
908    conn.execute('CREATE TABLE Movies (title text, director text, year integer);')
909    conn.execute('CREATE INDEX MovieNdx ON Music (title);')
910    conn.executemany('INSERT INTO Movies VALUES (?, ?, ?);', movie_data)
911    conn.commit()
912
913.. doctest::
914
915    >>> Movie('Star Wars').director
916    'George Lucas'
917    >>> jaws = Movie('Jaws')
918    >>> f'Released in {jaws.year} by {jaws.director}'
919    'Released in 1975 by Steven Spielberg'
920
921    >>> Song('Country Roads').artist
922    'John Denver'
923
924    >>> Movie('Star Wars').director = 'J.J. Abrams'
925    >>> Movie('Star Wars').director
926    'J.J. Abrams'
927
928
929Pure Python Equivalents
930^^^^^^^^^^^^^^^^^^^^^^^
931
932The descriptor protocol is simple and offers exciting possibilities.  Several
933use cases are so common that they have been prepackaged into built-in tools.
934Properties, bound methods, static methods, class methods, and \_\_slots\_\_ are
935all based on the descriptor protocol.
936
937
938Properties
939----------
940
941Calling :func:`property` is a succinct way of building a data descriptor that
942triggers a function call upon access to an attribute.  Its signature is::
943
944    property(fget=None, fset=None, fdel=None, doc=None) -> property
945
946The documentation shows a typical use to define a managed attribute ``x``:
947
948.. testcode::
949
950    class C:
951        def getx(self): return self.__x
952        def setx(self, value): self.__x = value
953        def delx(self): del self.__x
954        x = property(getx, setx, delx, "I'm the 'x' property.")
955
956.. doctest::
957    :hide:
958
959    >>> C.x.__doc__
960    "I'm the 'x' property."
961    >>> c.x = 2.71828
962    >>> c.x
963    2.71828
964    >>> del c.x
965    >>> c.x
966    Traceback (most recent call last):
967      ...
968    AttributeError: 'C' object has no attribute '_C__x'
969
970To see how :func:`property` is implemented in terms of the descriptor protocol,
971here is a pure Python equivalent:
972
973.. testcode::
974
975    class Property:
976        "Emulate PyProperty_Type() in Objects/descrobject.c"
977
978        def __init__(self, fget=None, fset=None, fdel=None, doc=None):
979            self.fget = fget
980            self.fset = fset
981            self.fdel = fdel
982            if doc is None and fget is not None:
983                doc = fget.__doc__
984            self.__doc__ = doc
985            self._name = ''
986
987        def __set_name__(self, owner, name):
988            self._name = name
989
990        def __get__(self, obj, objtype=None):
991            if obj is None:
992                return self
993            if self.fget is None:
994                raise AttributeError(f'unreadable attribute {self._name}')
995            return self.fget(obj)
996
997        def __set__(self, obj, value):
998            if self.fset is None:
999                raise AttributeError(f"can't set attribute {self._name}")
1000            self.fset(obj, value)
1001
1002        def __delete__(self, obj):
1003            if self.fdel is None:
1004                raise AttributeError(f"can't delete attribute {self._name}")
1005            self.fdel(obj)
1006
1007        def getter(self, fget):
1008            prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
1009            prop._name = self._name
1010            return prop
1011
1012        def setter(self, fset):
1013            prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
1014            prop._name = self._name
1015            return prop
1016
1017        def deleter(self, fdel):
1018            prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
1019            prop._name = self._name
1020            return prop
1021
1022.. testcode::
1023    :hide:
1024
1025    # Verify the Property() emulation
1026
1027    class CC:
1028        def getx(self):
1029            return self.__x
1030        def setx(self, value):
1031            self.__x = value
1032        def delx(self):
1033            del self.__x
1034        x = Property(getx, setx, delx, "I'm the 'x' property.")
1035
1036    # Now do it again but use the decorator style
1037
1038    class CCC:
1039        @Property
1040        def x(self):
1041            return self.__x
1042        @x.setter
1043        def x(self, value):
1044            self.__x = value
1045        @x.deleter
1046        def x(self):
1047            del self.__x
1048
1049
1050.. doctest::
1051    :hide:
1052
1053    >>> cc = CC()
1054    >>> hasattr(cc, 'x')
1055    False
1056    >>> cc.x = 33
1057    >>> cc.x
1058    33
1059    >>> del cc.x
1060    >>> hasattr(cc, 'x')
1061    False
1062
1063    >>> ccc = CCC()
1064    >>> hasattr(ccc, 'x')
1065    False
1066    >>> ccc.x = 333
1067    >>> ccc.x == 333
1068    True
1069    >>> del ccc.x
1070    >>> hasattr(ccc, 'x')
1071    False
1072
1073The :func:`property` builtin helps whenever a user interface has granted
1074attribute access and then subsequent changes require the intervention of a
1075method.
1076
1077For instance, a spreadsheet class may grant access to a cell value through
1078``Cell('b10').value``. Subsequent improvements to the program require the cell
1079to be recalculated on every access; however, the programmer does not want to
1080affect existing client code accessing the attribute directly.  The solution is
1081to wrap access to the value attribute in a property data descriptor:
1082
1083.. testcode::
1084
1085    class Cell:
1086        ...
1087
1088        @property
1089        def value(self):
1090            "Recalculate the cell before returning value"
1091            self.recalc()
1092            return self._value
1093
1094Either the built-in :func:`property` or our :func:`Property` equivalent would
1095work in this example.
1096
1097
1098Functions and methods
1099---------------------
1100
1101Python's object oriented features are built upon a function based environment.
1102Using non-data descriptors, the two are merged seamlessly.
1103
1104Functions stored in class dictionaries get turned into methods when invoked.
1105Methods only differ from regular functions in that the object instance is
1106prepended to the other arguments.  By convention, the instance is called
1107*self* but could be called *this* or any other variable name.
1108
1109Methods can be created manually with :class:`types.MethodType` which is
1110roughly equivalent to:
1111
1112.. testcode::
1113
1114    class MethodType:
1115        "Emulate PyMethod_Type in Objects/classobject.c"
1116
1117        def __init__(self, func, obj):
1118            self.__func__ = func
1119            self.__self__ = obj
1120
1121        def __call__(self, *args, **kwargs):
1122            func = self.__func__
1123            obj = self.__self__
1124            return func(obj, *args, **kwargs)
1125
1126To support automatic creation of methods, functions include the
1127:meth:`__get__` method for binding methods during attribute access.  This
1128means that functions are non-data descriptors that return bound methods
1129during dotted lookup from an instance.  Here's how it works:
1130
1131.. testcode::
1132
1133    class Function:
1134        ...
1135
1136        def __get__(self, obj, objtype=None):
1137            "Simulate func_descr_get() in Objects/funcobject.c"
1138            if obj is None:
1139                return self
1140            return MethodType(self, obj)
1141
1142Running the following class in the interpreter shows how the function
1143descriptor works in practice:
1144
1145.. testcode::
1146
1147    class D:
1148        def f(self, x):
1149             return x
1150
1151The function has a :term:`qualified name` attribute to support introspection:
1152
1153.. doctest::
1154
1155    >>> D.f.__qualname__
1156    'D.f'
1157
1158Accessing the function through the class dictionary does not invoke
1159:meth:`__get__`.  Instead, it just returns the underlying function object::
1160
1161    >>> D.__dict__['f']
1162    <function D.f at 0x00C45070>
1163
1164Dotted access from a class calls :meth:`__get__` which just returns the
1165underlying function unchanged::
1166
1167    >>> D.f
1168    <function D.f at 0x00C45070>
1169
1170The interesting behavior occurs during dotted access from an instance.  The
1171dotted lookup calls :meth:`__get__` which returns a bound method object::
1172
1173    >>> d = D()
1174    >>> d.f
1175    <bound method D.f of <__main__.D object at 0x00B18C90>>
1176
1177Internally, the bound method stores the underlying function and the bound
1178instance::
1179
1180    >>> d.f.__func__
1181    <function D.f at 0x00C45070>
1182
1183    >>> d.f.__self__
1184    <__main__.D object at 0x1012e1f98>
1185
1186If you have ever wondered where *self* comes from in regular methods or where
1187*cls* comes from in class methods, this is it!
1188
1189
1190Kinds of methods
1191----------------
1192
1193Non-data descriptors provide a simple mechanism for variations on the usual
1194patterns of binding functions into methods.
1195
1196To recap, functions have a :meth:`__get__` method so that they can be converted
1197to a method when accessed as attributes.  The non-data descriptor transforms an
1198``obj.f(*args)`` call into ``f(obj, *args)``.  Calling ``cls.f(*args)``
1199becomes ``f(*args)``.
1200
1201This chart summarizes the binding and its two most useful variants:
1202
1203      +-----------------+----------------------+------------------+
1204      | Transformation  | Called from an       | Called from a    |
1205      |                 | object               | class            |
1206      +=================+======================+==================+
1207      | function        | f(obj, \*args)       | f(\*args)        |
1208      +-----------------+----------------------+------------------+
1209      | staticmethod    | f(\*args)            | f(\*args)        |
1210      +-----------------+----------------------+------------------+
1211      | classmethod     | f(type(obj), \*args) | f(cls, \*args)   |
1212      +-----------------+----------------------+------------------+
1213
1214
1215Static methods
1216--------------
1217
1218Static methods return the underlying function without changes.  Calling either
1219``c.f`` or ``C.f`` is the equivalent of a direct lookup into
1220``object.__getattribute__(c, "f")`` or ``object.__getattribute__(C, "f")``. As a
1221result, the function becomes identically accessible from either an object or a
1222class.
1223
1224Good candidates for static methods are methods that do not reference the
1225``self`` variable.
1226
1227For instance, a statistics package may include a container class for
1228experimental data.  The class provides normal methods for computing the average,
1229mean, median, and other descriptive statistics that depend on the data. However,
1230there may be useful functions which are conceptually related but do not depend
1231on the data.  For instance, ``erf(x)`` is handy conversion routine that comes up
1232in statistical work but does not directly depend on a particular dataset.
1233It can be called either from an object or the class:  ``s.erf(1.5) --> .9332`` or
1234``Sample.erf(1.5) --> .9332``.
1235
1236Since static methods return the underlying function with no changes, the
1237example calls are unexciting:
1238
1239.. testcode::
1240
1241    class E:
1242        @staticmethod
1243        def f(x):
1244            return x * 10
1245
1246.. doctest::
1247
1248    >>> E.f(3)
1249    30
1250    >>> E().f(3)
1251    30
1252
1253Using the non-data descriptor protocol, a pure Python version of
1254:func:`staticmethod` would look like this:
1255
1256.. testcode::
1257
1258    class StaticMethod:
1259        "Emulate PyStaticMethod_Type() in Objects/funcobject.c"
1260
1261        def __init__(self, f):
1262            self.f = f
1263
1264        def __get__(self, obj, objtype=None):
1265            return self.f
1266
1267        def __call__(self, *args, **kwds):
1268            return self.f(*args, **kwds)
1269
1270.. testcode::
1271    :hide:
1272
1273    class E_sim:
1274        @StaticMethod
1275        def f(x):
1276            return x * 10
1277
1278    wrapped_ord = StaticMethod(ord)
1279
1280.. doctest::
1281    :hide:
1282
1283    >>> E_sim.f(3)
1284    30
1285    >>> E_sim().f(3)
1286    30
1287    >>> wrapped_ord('A')
1288    65
1289
1290
1291Class methods
1292-------------
1293
1294Unlike static methods, class methods prepend the class reference to the
1295argument list before calling the function.  This format is the same
1296for whether the caller is an object or a class:
1297
1298.. testcode::
1299
1300    class F:
1301        @classmethod
1302        def f(cls, x):
1303            return cls.__name__, x
1304
1305.. doctest::
1306
1307    >>> F.f(3)
1308    ('F', 3)
1309    >>> F().f(3)
1310    ('F', 3)
1311
1312This behavior is useful whenever the method only needs to have a class
1313reference and does not rely on data stored in a specific instance.  One use for
1314class methods is to create alternate class constructors.  For example, the
1315classmethod :func:`dict.fromkeys` creates a new dictionary from a list of
1316keys.  The pure Python equivalent is:
1317
1318.. testcode::
1319
1320    class Dict(dict):
1321        @classmethod
1322        def fromkeys(cls, iterable, value=None):
1323            "Emulate dict_fromkeys() in Objects/dictobject.c"
1324            d = cls()
1325            for key in iterable:
1326                d[key] = value
1327            return d
1328
1329Now a new dictionary of unique keys can be constructed like this:
1330
1331.. doctest::
1332
1333    >>> d = Dict.fromkeys('abracadabra')
1334    >>> type(d) is Dict
1335    True
1336    >>> d
1337    {'a': None, 'b': None, 'r': None, 'c': None, 'd': None}
1338
1339Using the non-data descriptor protocol, a pure Python version of
1340:func:`classmethod` would look like this:
1341
1342.. testcode::
1343
1344    class ClassMethod:
1345        "Emulate PyClassMethod_Type() in Objects/funcobject.c"
1346
1347        def __init__(self, f):
1348            self.f = f
1349
1350        def __get__(self, obj, cls=None):
1351            if cls is None:
1352                cls = type(obj)
1353            if hasattr(type(self.f), '__get__'):
1354                return self.f.__get__(cls, cls)
1355            return MethodType(self.f, cls)
1356
1357.. testcode::
1358    :hide:
1359
1360    # Verify the emulation works
1361    class T:
1362        @ClassMethod
1363        def cm(cls, x, y):
1364            return (cls, x, y)
1365
1366        @ClassMethod
1367        @property
1368        def __doc__(cls):
1369            return f'A doc for {cls.__name__!r}'
1370
1371
1372.. doctest::
1373    :hide:
1374
1375    >>> T.cm(11, 22)
1376    (<class 'T'>, 11, 22)
1377
1378    # Also call it from an instance
1379    >>> t = T()
1380    >>> t.cm(11, 22)
1381    (<class 'T'>, 11, 22)
1382
1383    # Check the alternate path for chained descriptors
1384    >>> T.__doc__
1385    "A doc for 'T'"
1386
1387
1388The code path for ``hasattr(type(self.f), '__get__')`` was added in
1389Python 3.9 and makes it possible for :func:`classmethod` to support
1390chained decorators.  For example, a classmethod and property could be
1391chained together:
1392
1393.. testcode::
1394
1395    class G:
1396        @classmethod
1397        @property
1398        def __doc__(cls):
1399            return f'A doc for {cls.__name__!r}'
1400
1401.. doctest::
1402
1403    >>> G.__doc__
1404    "A doc for 'G'"
1405
1406
1407Member objects and __slots__
1408----------------------------
1409
1410When a class defines ``__slots__``, it replaces instance dictionaries with a
1411fixed-length array of slot values.  From a user point of view that has
1412several effects:
1413
14141. Provides immediate detection of bugs due to misspelled attribute
1415assignments.  Only attribute names specified in ``__slots__`` are allowed:
1416
1417.. testcode::
1418
1419        class Vehicle:
1420            __slots__ = ('id_number', 'make', 'model')
1421
1422.. doctest::
1423
1424        >>> auto = Vehicle()
1425        >>> auto.id_nubmer = 'VYE483814LQEX'
1426        Traceback (most recent call last):
1427            ...
1428        AttributeError: 'Vehicle' object has no attribute 'id_nubmer'
1429
14302. Helps create immutable objects where descriptors manage access to private
1431attributes stored in ``__slots__``:
1432
1433.. testcode::
1434
1435    class Immutable:
1436
1437        __slots__ = ('_dept', '_name')          # Replace the instance dictionary
1438
1439        def __init__(self, dept, name):
1440            self._dept = dept                   # Store to private attribute
1441            self._name = name                   # Store to private attribute
1442
1443        @property                               # Read-only descriptor
1444        def dept(self):
1445            return self._dept
1446
1447        @property
1448        def name(self):                         # Read-only descriptor
1449            return self._name
1450
1451.. doctest::
1452
1453    >>> mark = Immutable('Botany', 'Mark Watney')
1454    >>> mark.dept
1455    'Botany'
1456    >>> mark.dept = 'Space Pirate'
1457    Traceback (most recent call last):
1458        ...
1459    AttributeError: can't set attribute
1460    >>> mark.location = 'Mars'
1461    Traceback (most recent call last):
1462        ...
1463    AttributeError: 'Immutable' object has no attribute 'location'
1464
14653. Saves memory.  On a 64-bit Linux build, an instance with two attributes
1466takes 48 bytes with ``__slots__`` and 152 bytes without.  This `flyweight
1467design pattern <https://en.wikipedia.org/wiki/Flyweight_pattern>`_ likely only
1468matters when a large number of instances are going to be created.
1469
14704. Improves speed.  Reading instance variables is 35% faster with
1471``__slots__`` (as measured with Python 3.10 on an Apple M1 processor).
1472
14735. Blocks tools like :func:`functools.cached_property` which require an
1474instance dictionary to function correctly:
1475
1476.. testcode::
1477
1478    from functools import cached_property
1479
1480    class CP:
1481        __slots__ = ()                          # Eliminates the instance dict
1482
1483        @cached_property                        # Requires an instance dict
1484        def pi(self):
1485            return 4 * sum((-1.0)**n / (2.0*n + 1.0)
1486                           for n in reversed(range(100_000)))
1487
1488.. doctest::
1489
1490    >>> CP().pi
1491    Traceback (most recent call last):
1492      ...
1493    TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property.
1494
1495It is not possible to create an exact drop-in pure Python version of
1496``__slots__`` because it requires direct access to C structures and control
1497over object memory allocation.  However, we can build a mostly faithful
1498simulation where the actual C structure for slots is emulated by a private
1499``_slotvalues`` list.  Reads and writes to that private structure are managed
1500by member descriptors:
1501
1502.. testcode::
1503
1504    null = object()
1505
1506    class Member:
1507
1508        def __init__(self, name, clsname, offset):
1509            'Emulate PyMemberDef in Include/structmember.h'
1510            # Also see descr_new() in Objects/descrobject.c
1511            self.name = name
1512            self.clsname = clsname
1513            self.offset = offset
1514
1515        def __get__(self, obj, objtype=None):
1516            'Emulate member_get() in Objects/descrobject.c'
1517            # Also see PyMember_GetOne() in Python/structmember.c
1518            value = obj._slotvalues[self.offset]
1519            if value is null:
1520                raise AttributeError(self.name)
1521            return value
1522
1523        def __set__(self, obj, value):
1524            'Emulate member_set() in Objects/descrobject.c'
1525            obj._slotvalues[self.offset] = value
1526
1527        def __delete__(self, obj):
1528            'Emulate member_delete() in Objects/descrobject.c'
1529            value = obj._slotvalues[self.offset]
1530            if value is null:
1531                raise AttributeError(self.name)
1532            obj._slotvalues[self.offset] = null
1533
1534        def __repr__(self):
1535            'Emulate member_repr() in Objects/descrobject.c'
1536            return f'<Member {self.name!r} of {self.clsname!r}>'
1537
1538The :meth:`type.__new__` method takes care of adding member objects to class
1539variables:
1540
1541.. testcode::
1542
1543    class Type(type):
1544        'Simulate how the type metaclass adds member objects for slots'
1545
1546        def __new__(mcls, clsname, bases, mapping):
1547            'Emuluate type_new() in Objects/typeobject.c'
1548            # type_new() calls PyTypeReady() which calls add_methods()
1549            slot_names = mapping.get('slot_names', [])
1550            for offset, name in enumerate(slot_names):
1551                mapping[name] = Member(name, clsname, offset)
1552            return type.__new__(mcls, clsname, bases, mapping)
1553
1554The :meth:`object.__new__` method takes care of creating instances that have
1555slots instead of an instance dictionary.  Here is a rough simulation in pure
1556Python:
1557
1558.. testcode::
1559
1560    class Object:
1561        'Simulate how object.__new__() allocates memory for __slots__'
1562
1563        def __new__(cls, *args):
1564            'Emulate object_new() in Objects/typeobject.c'
1565            inst = super().__new__(cls)
1566            if hasattr(cls, 'slot_names'):
1567                empty_slots = [null] * len(cls.slot_names)
1568                object.__setattr__(inst, '_slotvalues', empty_slots)
1569            return inst
1570
1571        def __setattr__(self, name, value):
1572            'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1573            cls = type(self)
1574            if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1575                raise AttributeError(
1576                    f'{type(self).__name__!r} object has no attribute {name!r}'
1577                )
1578            super().__setattr__(name, value)
1579
1580        def __delattr__(self, name):
1581            'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1582            cls = type(self)
1583            if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1584                raise AttributeError(
1585                    f'{type(self).__name__!r} object has no attribute {name!r}'
1586                )
1587            super().__delattr__(name)
1588
1589To use the simulation in a real class, just inherit from :class:`Object` and
1590set the :term:`metaclass` to :class:`Type`:
1591
1592.. testcode::
1593
1594    class H(Object, metaclass=Type):
1595        'Instance variables stored in slots'
1596
1597        slot_names = ['x', 'y']
1598
1599        def __init__(self, x, y):
1600            self.x = x
1601            self.y = y
1602
1603At this point, the metaclass has loaded member objects for *x* and *y*::
1604
1605    >>> from pprint import pp
1606    >>> pp(dict(vars(H)))
1607    {'__module__': '__main__',
1608     '__doc__': 'Instance variables stored in slots',
1609     'slot_names': ['x', 'y'],
1610     '__init__': <function H.__init__ at 0x7fb5d302f9d0>,
1611     'x': <Member 'x' of 'H'>,
1612     'y': <Member 'y' of 'H'>}
1613
1614.. doctest::
1615    :hide:
1616
1617    # We test this separately because the preceding section is not
1618    # doctestable due to the hex memory address for the __init__ function
1619    >>> isinstance(vars(H)['x'], Member)
1620    True
1621    >>> isinstance(vars(H)['y'], Member)
1622    True
1623
1624When instances are created, they have a ``slot_values`` list where the
1625attributes are stored:
1626
1627.. doctest::
1628
1629    >>> h = H(10, 20)
1630    >>> vars(h)
1631    {'_slotvalues': [10, 20]}
1632    >>> h.x = 55
1633    >>> vars(h)
1634    {'_slotvalues': [55, 20]}
1635
1636Misspelled or unassigned attributes will raise an exception:
1637
1638.. doctest::
1639
1640    >>> h.xz
1641    Traceback (most recent call last):
1642        ...
1643    AttributeError: 'H' object has no attribute 'xz'
1644
1645.. doctest::
1646   :hide:
1647
1648    # Examples for deleted attributes are not shown because this section
1649    # is already a bit lengthy.  We still test that code here.
1650    >>> del h.x
1651    >>> hasattr(h, 'x')
1652    False
1653
1654    # Also test the code for uninitialized slots
1655    >>> class HU(Object, metaclass=Type):
1656    ...     slot_names = ['x', 'y']
1657    ...
1658    >>> hu = HU()
1659    >>> hasattr(hu, 'x')
1660    False
1661    >>> hasattr(hu, 'y')
1662    False
1663