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