blob: bf026f4b7e61bee2a31b1ed8203480e16b0646d7 [file] [log] [blame]
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001.. _descriptorhowto:
2
Georg Brandl45cceeb2010-05-19 21:39:51 +00003======================
4Descriptor HowTo Guide
5======================
6
7:Author: Raymond Hettinger
8:Contact: <python at rcn dot com>
9
10.. Contents::
11
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070012
13:term:`Descriptors <descriptor>` let objects customize attribute lookup,
14storage, and deletion.
15
Raymond Hettingere6a7ea42020-10-25 07:12:50 -070016This guide has four major sections:
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070017
181) The "primer" gives a basic overview, moving gently from simple examples,
Raymond Hettingerc272d402020-11-15 17:44:28 -080019 adding one feature at a time. Start here if you're new to descriptors.
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070020
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
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700284) 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
Raymond Hettingere9208f02020-11-01 20:15:50 -080030 into bound methods or about the implementation of common tools like
31 :func:`classmethod`, :func:`staticmethod`, :func:`property`, and
32 :term:`__slots__`.
Raymond Hettingere6a7ea42020-10-25 07:12:50 -070033
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070034
35Primer
36^^^^^^
37
Raymond Hettinger4a9c6372020-10-24 20:34:39 -070038In this primer, we start with the most basic possible example and then we'll
39add new capabilities one by one.
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070040
41
42Simple example: A descriptor that returns a constant
43----------------------------------------------------
44
Raymond Hettinger755c6e62021-02-04 22:05:42 -080045The :class:`Ten` class is a descriptor whose :meth:`__get__` method always
46returns the constant ``10``:
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070047
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -080048.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070049
50 class Ten:
51 def __get__(self, obj, objtype=None):
52 return 10
53
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -080054To use the descriptor, it must be stored as a class variable in another class:
55
56.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070057
58 class A:
59 x = 5 # Regular class attribute
Raymond Hettinger148c76b2020-11-01 09:10:06 -080060 y = Ten() # Descriptor instance
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070061
62An interactive session shows the difference between normal attribute lookup
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -080063and descriptor lookup:
64
65.. doctest::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070066
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
Raymond Hettinger755c6e62021-02-04 22:05:42 -080073In 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``.
Raymond Hettingerc272d402020-11-15 17:44:28 -080077
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070078Note 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
Raymond Hettingerc272d402020-11-15 17:44:28 -080090Interesting descriptors typically run computations instead of returning
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -080091constants:
92
93.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070094
Raymond Hettinger8d3d7312020-10-23 12:55:39 -070095 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
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800104 size = DirectorySize() # Descriptor instance
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700105
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
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700112 >>> s = Directory('songs')
Raymond Hettingerc272d402020-11-15 17:44:28 -0800113 >>> g = Directory('games')
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700114 >>> s.size # The songs directory has twenty files
115 20
Raymond Hettingerc272d402020-11-15 17:44:28 -0800116 >>> g.size # The games directory has three files
117 3
Raymond Hettingerc5354c02021-04-03 13:09:01 -0700118 >>> os.remove('games/chess') # Delete a game
Raymond Hettingerc272d402020-11-15 17:44:28 -0800119 >>> g.size # File count is automatically updated
Raymond Hettingerc5354c02021-04-03 13:09:01 -0700120 2
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700121
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
Raymond Hettinger80318772020-11-06 01:30:17 -0800125either *g* or *s*, an instance of *Directory*. It is the *obj* parameter that
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700126lets 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
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800141the lookup or update:
142
143.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700144
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
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800162 age = LoggedAgeAccess() # Descriptor instance
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700163
164 def __init__(self, name, age):
165 self.name = name # Regular instance attribute
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800166 self.age = age # Calls __set__()
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700167
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
Raymond Hettinger85c84922020-11-25 01:54:24 -0800173logged, 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::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700182
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
Raymond Hettinger80318772020-11-06 01:30:17 -0800206One major issue with this example is that the private name *_age* is hardwired in
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700207the *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
Raymond Hettingere9208f02020-11-01 20:15:50 -0800212Customized names
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700213----------------
214
Raymond Hettinger80318772020-11-06 01:30:17 -0800215When a class uses descriptors, it can inform each descriptor about which
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700216variable 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
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800221be recorded, giving each descriptor its own *public_name* and *private_name*:
222
223.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700224
225 import logging
226
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700227 logging.basicConfig(level=logging.INFO)
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700228
229 class LoggedAccess:
230
231 def __set_name__(self, owner, name):
232 self.public_name = name
Raymond Hettingerc272d402020-11-15 17:44:28 -0800233 self.private_name = '_' + name
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700234
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
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800246 name = LoggedAccess() # First descriptor instance
247 age = LoggedAccess() # Second descriptor instance
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700248
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
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800258we call :func:`vars` to look up the descriptor without triggering it:
259
260.. doctest::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700261
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
Raymond Hettinger85c84922020-11-25 01:54:24 -0800267The 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::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700276
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
Raymond Hettingere4c88952021-04-03 13:07:52 -0700284The two *Person* instances contain only the private names:
285
286.. doctest::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700287
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
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700300Optionally, descriptors can have a :meth:`__set_name__` method. This is only
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700301used in cases where a descriptor needs to know either the class where it was
Raymond Hettingerc272d402020-11-15 17:44:28 -0800302created or the name of class variable it was assigned to. (This method, if
303present, is called even if the class is not a descriptor.)
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700304
Raymond Hettinger755c6e62021-02-04 22:05:42 -0800305Descriptors get invoked by the dot operator during attribute lookup. If a
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700306descriptor 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
Raymond Hettingerc272d402020-11-15 17:44:28 -0800313stored in class variables to control what happens during attribute lookup.
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700314
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
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700338prevent data corruption at its source.
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700339
340This :class:`Validator` class is both an :term:`abstract base class` and a
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800341managed attribute descriptor:
342
343.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700344
345 from abc import ABC, abstractmethod
346
347 class Validator(ABC):
348
349 def __set_name__(self, owner, name):
Raymond Hettingerc272d402020-11-15 17:44:28 -0800350 self.private_name = '_' + name
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700351
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
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700363Custom validators need to inherit from :class:`Validator` and must supply a
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700364: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
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700379 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.
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700382
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800383.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700384
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
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800436Practical application
437---------------------
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700438
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800439Here's how the data validators can be used in a real class:
440
441.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700442
443 class Component:
444
445 name = String(minsize=3, maxsize=10, predicate=str.isupper)
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700446 kind = OneOf('wood', 'metal', 'plastic')
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700447 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
Raymond Hettinger85c84922020-11-25 01:54:24 -0800454The descriptors prevent invalid instances from being created:
455
456.. doctest::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700457
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800458 >>> 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
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700478
479
480Technical Tutorial
481^^^^^^^^^^^^^^^^^^
482
483What follows is a more technical tutorial for the mechanics and details of how
484descriptors work.
485
486
Georg Brandl45cceeb2010-05-19 21:39:51 +0000487Abstract
488--------
489
490Defines descriptors, summarizes the protocol, and shows how descriptors are
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700491called. Provides an example showing how object relational mappings work.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000492
493Learning about descriptors not only provides access to a larger toolset, it
Raymond Hettingerc272d402020-11-15 17:44:28 -0800494creates a deeper understanding of how Python works.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000495
496
Raymond Hettingere9208f02020-11-01 20:15:50 -0800497Definition and introduction
Georg Brandl45cceeb2010-05-19 21:39:51 +0000498---------------------------
499
Raymond Hettingerc272d402020-11-15 17:44:28 -0800500In general, a descriptor is an attribute value that has one of the methods in
501the descriptor protocol. Those methods are :meth:`__get__`, :meth:`__set__`,
diegoea98fe022021-02-02 22:28:36 -0500502and :meth:`__delete__`. If any of those methods are defined for an
Raymond Hettingerc272d402020-11-15 17:44:28 -0800503attribute, it is said to be a :term:`descriptor`.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000504
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
Raymond Hettingerc272d402020-11-15 17:44:28 -0800508continuing through the method resolution order of ``type(a)``. If the
Georg Brandl45cceeb2010-05-19 21:39:51 +0000509looked-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
Florent Xiclunaaa6c1d22011-12-12 18:54:29 +0100512were defined.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000513
514Descriptors are a powerful, general purpose protocol. They are the mechanism
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700515behind 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.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000519
520
Raymond Hettingere9208f02020-11-01 20:15:50 -0800521Descriptor protocol
Georg Brandl45cceeb2010-05-19 21:39:51 +0000522-------------------
523
NotAFile28ea4c22018-09-10 23:35:38 +0200524``descr.__get__(self, obj, type=None) -> value``
Georg Brandl45cceeb2010-05-19 21:39:51 +0000525
NotAFile28ea4c22018-09-10 23:35:38 +0200526``descr.__set__(self, obj, value) -> None``
Georg Brandl45cceeb2010-05-19 21:39:51 +0000527
NotAFile28ea4c22018-09-10 23:35:38 +0200528``descr.__delete__(self, obj) -> None``
Georg Brandl45cceeb2010-05-19 21:39:51 +0000529
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
Aaron Hall, MBA4054b172018-05-20 19:46:42 -0400534If an object defines :meth:`__set__` or :meth:`__delete__`, it is considered
Georg Brandl45cceeb2010-05-19 21:39:51 +0000535a data descriptor. Descriptors that only define :meth:`__get__` are called
Raymond Hettingerc272d402020-11-15 17:44:28 -0800536non-data descriptors (they are often used for methods but other uses are
Georg Brandl45cceeb2010-05-19 21:39:51 +0000537possible).
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
Raymond Hettingere9208f02020-11-01 20:15:50 -0800551Overview of descriptor invocation
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800552---------------------------------
Georg Brandl45cceeb2010-05-19 21:39:51 +0000553
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800554A descriptor can be called directly with ``desc.__get__(obj)`` or
555``desc.__get__(None, cls)``.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000556
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700557But it is more common for a descriptor to be invoked automatically from
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800558attribute access.
559
560The expression ``obj.x`` looks up the attribute ``x`` in the chain of
Raymond Hettingerc272d402020-11-15 17:44:28 -0800561namespaces 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.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000564
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700565The details of invocation depend on whether ``obj`` is an object, class, or
566instance of super.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000567
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700568
Raymond Hettingere9208f02020-11-01 20:15:50 -0800569Invocation from an instance
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800570---------------------------
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700571
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800572Instance 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.
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700576
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800577If a descriptor is found for ``a.x``, then it is invoked with:
578``desc.__get__(a, type(a))``.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000579
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800580The logic for a dotted lookup is in :meth:`object.__getattribute__`. Here is
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800581a pure Python equivalent:
582
583.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +0000584
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800585 def object_getattribute(obj, name):
586 "Emulate PyObject_GenericGetAttr() in Objects/object.c"
587 null = object()
588 objtype = type(obj)
Raymond Hettingerc272d402020-11-15 17:44:28 -0800589 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
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800601 raise AttributeError(name)
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700602
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800603
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
Raymond Hettingerc272d402020-11-15 17:44:28 -0800700Interestingly, attribute lookup doesn't call :meth:`object.__getattribute__`
701directly. Instead, both the dot operator and the :func:`getattr` function
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800702perform attribute lookup by way of a helper function:
703
704.. testcode::
Raymond Hettingerc272d402020-11-15 17:44:28 -0800705
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
Raymond Hettingere4c88952021-04-03 13:07:52 -0700715.. 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
Raymond Hettingerc272d402020-11-15 17:44:28 -0800747So 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.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000752
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800753
Raymond Hettingere9208f02020-11-01 20:15:50 -0800754Invocation from a class
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800755-----------------------
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
Raymond Hettingere9208f02020-11-01 20:15:50 -0800768Invocation from super
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800769---------------------
770
771The logic for super's dotted lookup is in the :meth:`__getattribute__` method for
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700772object returned by :class:`super()`.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000773
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800774A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__``
775for the base class ``B`` immediately following ``A`` and then returns
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700776``B.__dict__['m'].__get__(obj, A)``. If not a descriptor, ``m`` is returned
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800777unchanged.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000778
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800779The full C implementation can be found in :c:func:`super_getattro()` in
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700780:source:`Objects/typeobject.c`. A pure Python equivalent can be found in
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800781`Guido's Tutorial
782<https://www.python.org/download/releases/2.2.3/descrintro/#cooperation>`_.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000783
Georg Brandl45cceeb2010-05-19 21:39:51 +0000784
Raymond Hettingere9208f02020-11-01 20:15:50 -0800785Summary of invocation logic
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800786---------------------------
787
788The mechanism for descriptors is embedded in the :meth:`__getattribute__()`
789methods for :class:`object`, :class:`type`, and :func:`super`.
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700790
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.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000809
810
Raymond Hettingere9208f02020-11-01 20:15:50 -0800811Automatic name notification
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700812---------------------------
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
Raymond Hettinger80318772020-11-06 01:30:17 -0800818arguments. The *owner* is the class where the descriptor is used, and the
819*name* is the class variable the descriptor was assigned to.
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700820
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
Raymond Hettingere9208f02020-11-01 20:15:50 -0800829ORM example
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700830-----------
Georg Brandl45cceeb2010-05-19 21:39:51 +0000831
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700832The 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>`_.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000835
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700836The 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
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800838care of lookups or updates:
839
840.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +0000841
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700842 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}=?;'
Georg Brandl45cceeb2010-05-19 21:39:51 +0000847
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700848 def __get__(self, obj, objtype=None):
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700849 return conn.execute(self.fetch, [obj.key]).fetchone()[0]
Georg Brandl45cceeb2010-05-19 21:39:51 +0000850
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700851 def __set__(self, obj, value):
852 conn.execute(self.store, [value, obj.key])
853 conn.commit()
Georg Brandl45cceeb2010-05-19 21:39:51 +0000854
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800855We 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::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -0700860
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700861 class Movie:
862 table = 'Movies' # Table name
863 key = 'title' # Primary key
864 director = Field()
865 year = Field()
Georg Brandl45cceeb2010-05-19 21:39:51 +0000866
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700867 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
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800880To use the models, first connect to the database::
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700881
882 >>> import sqlite3
883 >>> conn = sqlite3.connect('entertainment.db')
884
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800885An 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
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700915 >>> 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
Raymond Hettingerc272d402020-11-15 17:44:28 -0800928
Raymond Hettingere6a7ea42020-10-25 07:12:50 -0700929Pure Python Equivalents
930^^^^^^^^^^^^^^^^^^^^^^^
931
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700932The descriptor protocol is simple and offers exciting possibilities. Several
Raymond Hettinger148c76b2020-11-01 09:10:06 -0800933use cases are so common that they have been prepackaged into built-in tools.
Raymond Hettingere9208f02020-11-01 20:15:50 -0800934Properties, bound methods, static methods, class methods, and \_\_slots\_\_ are
935all based on the descriptor protocol.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000936
937
938Properties
939----------
940
941Calling :func:`property` is a succinct way of building a data descriptor that
Raymond Hettinger80318772020-11-06 01:30:17 -0800942triggers a function call upon access to an attribute. Its signature is::
Georg Brandl45cceeb2010-05-19 21:39:51 +0000943
Raymond Hettinger4a9c6372020-10-24 20:34:39 -0700944 property(fget=None, fset=None, fdel=None, doc=None) -> property
Georg Brandl45cceeb2010-05-19 21:39:51 +0000945
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800946The documentation shows a typical use to define a managed attribute ``x``:
947
948.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +0000949
Serhiy Storchakae042a452019-06-10 13:35:52 +0300950 class C:
Georg Brandl45cceeb2010-05-19 21:39:51 +0000951 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
956To see how :func:`property` is implemented in terms of the descriptor protocol,
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800957here is a pure Python equivalent:
958
959.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +0000960
Serhiy Storchakae042a452019-06-10 13:35:52 +0300961 class Property:
Georg Brandl45cceeb2010-05-19 21:39:51 +0000962 "Emulate PyProperty_Type() in Objects/descrobject.c"
963
964 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
965 self.fget = fget
966 self.fset = fset
967 self.fdel = fdel
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700968 if doc is None and fget is not None:
969 doc = fget.__doc__
Georg Brandl45cceeb2010-05-19 21:39:51 +0000970 self.__doc__ = doc
Yurii Karabasc56387f2020-12-30 11:51:24 +0200971 self._name = ''
972
973 def __set_name__(self, owner, name):
974 self._name = name
Georg Brandl45cceeb2010-05-19 21:39:51 +0000975
976 def __get__(self, obj, objtype=None):
977 if obj is None:
978 return self
979 if self.fget is None:
Yurii Karabasc56387f2020-12-30 11:51:24 +0200980 raise AttributeError(f'unreadable attribute {self._name}')
Georg Brandl45cceeb2010-05-19 21:39:51 +0000981 return self.fget(obj)
982
983 def __set__(self, obj, value):
984 if self.fset is None:
Yurii Karabasc56387f2020-12-30 11:51:24 +0200985 raise AttributeError(f"can't set attribute {self._name}")
Georg Brandl45cceeb2010-05-19 21:39:51 +0000986 self.fset(obj, value)
987
988 def __delete__(self, obj):
989 if self.fdel is None:
Yurii Karabasc56387f2020-12-30 11:51:24 +0200990 raise AttributeError(f"can't delete attribute {self._name}")
Georg Brandl45cceeb2010-05-19 21:39:51 +0000991 self.fdel(obj)
992
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700993 def getter(self, fget):
Yurii Karabasc56387f2020-12-30 11:51:24 +0200994 prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
995 prop._name = self._name
996 return prop
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700997
998 def setter(self, fset):
Yurii Karabasc56387f2020-12-30 11:51:24 +0200999 prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
1000 prop._name = self._name
1001 return prop
Raymond Hettinger632c8c82013-03-10 09:41:18 -07001002
1003 def deleter(self, fdel):
Yurii Karabasc56387f2020-12-30 11:51:24 +02001004 prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
1005 prop._name = self._name
1006 return prop
Raymond Hettinger632c8c82013-03-10 09:41:18 -07001007
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001008.. testcode::
1009 :hide:
1010
1011 # Verify the Property() emulation
1012
1013 class CC:
1014 def getx(self):
1015 return self.__x
1016 def setx(self, value):
1017 self.__x = value
1018 def delx(self):
1019 del self.__x
1020 x = Property(getx, setx, delx, "I'm the 'x' property.")
1021
1022 # Now do it again but use the decorator style
1023
1024 class CCC:
1025 @Property
1026 def x(self):
1027 return self.__x
1028 @x.setter
1029 def x(self, value):
1030 self.__x = value
1031 @x.deleter
1032 def x(self):
1033 del self.__x
1034
1035
1036.. doctest::
1037 :hide:
1038
1039 >>> cc = CC()
1040 >>> hasattr(cc, 'x')
1041 False
1042 >>> cc.x = 33
1043 >>> cc.x
1044 33
1045 >>> del cc.x
1046 >>> hasattr(cc, 'x')
1047 False
1048
1049 >>> ccc = CCC()
1050 >>> hasattr(ccc, 'x')
1051 False
1052 >>> ccc.x = 333
1053 >>> ccc.x == 333
1054 True
1055 >>> del ccc.x
1056 >>> hasattr(ccc, 'x')
1057 False
1058
Georg Brandl45cceeb2010-05-19 21:39:51 +00001059The :func:`property` builtin helps whenever a user interface has granted
1060attribute access and then subsequent changes require the intervention of a
1061method.
1062
1063For instance, a spreadsheet class may grant access to a cell value through
1064``Cell('b10').value``. Subsequent improvements to the program require the cell
1065to be recalculated on every access; however, the programmer does not want to
1066affect existing client code accessing the attribute directly. The solution is
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001067to wrap access to the value attribute in a property data descriptor:
1068
1069.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001070
Serhiy Storchakae042a452019-06-10 13:35:52 +03001071 class Cell:
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001072 ...
1073
1074 @property
1075 def value(self):
_ = NaNb066edf2017-06-23 11:54:35 +08001076 "Recalculate the cell before returning value"
Georg Brandl45cceeb2010-05-19 21:39:51 +00001077 self.recalc()
_ = NaNb066edf2017-06-23 11:54:35 +08001078 return self._value
Georg Brandl45cceeb2010-05-19 21:39:51 +00001079
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001080Either the built-in :func:`property` or our :func:`Property` equivalent would
1081work in this example.
1082
Georg Brandl45cceeb2010-05-19 21:39:51 +00001083
Raymond Hettingere9208f02020-11-01 20:15:50 -08001084Functions and methods
Georg Brandl45cceeb2010-05-19 21:39:51 +00001085---------------------
1086
1087Python's object oriented features are built upon a function based environment.
1088Using non-data descriptors, the two are merged seamlessly.
1089
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001090Functions stored in class dictionaries get turned into methods when invoked.
1091Methods only differ from regular functions in that the object instance is
1092prepended to the other arguments. By convention, the instance is called
1093*self* but could be called *this* or any other variable name.
Georg Brandl45cceeb2010-05-19 21:39:51 +00001094
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001095Methods can be created manually with :class:`types.MethodType` which is
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001096roughly equivalent to:
1097
1098.. testcode::
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001099
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001100 class MethodType:
Zackery Spytze689cdc2021-04-01 11:03:33 -06001101 "Emulate PyMethod_Type in Objects/classobject.c"
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001102
1103 def __init__(self, func, obj):
1104 self.__func__ = func
1105 self.__self__ = obj
1106
1107 def __call__(self, *args, **kwargs):
1108 func = self.__func__
1109 obj = self.__self__
1110 return func(obj, *args, **kwargs)
1111
1112To support automatic creation of methods, functions include the
1113:meth:`__get__` method for binding methods during attribute access. This
Raymond Hettinger80318772020-11-06 01:30:17 -08001114means that functions are non-data descriptors that return bound methods
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001115during dotted lookup from an instance. Here's how it works:
1116
1117.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001118
Serhiy Storchakae042a452019-06-10 13:35:52 +03001119 class Function:
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001120 ...
1121
Georg Brandl45cceeb2010-05-19 21:39:51 +00001122 def __get__(self, obj, objtype=None):
1123 "Simulate func_descr_get() in Objects/funcobject.c"
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001124 if obj is None:
1125 return self
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001126 return MethodType(self, obj)
Georg Brandl45cceeb2010-05-19 21:39:51 +00001127
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001128Running the following class in the interpreter shows how the function
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001129descriptor works in practice:
1130
1131.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001132
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001133 class D:
1134 def f(self, x):
1135 return x
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001136
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001137The function has a :term:`qualified name` attribute to support introspection:
1138
1139.. doctest::
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001140
1141 >>> D.f.__qualname__
1142 'D.f'
1143
1144Accessing the function through the class dictionary does not invoke
1145:meth:`__get__`. Instead, it just returns the underlying function object::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001146
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001147 >>> D.__dict__['f']
1148 <function D.f at 0x00C45070>
1149
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001150Dotted access from a class calls :meth:`__get__` which just returns the
1151underlying function unchanged::
1152
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001153 >>> D.f
1154 <function D.f at 0x00C45070>
1155
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001156The interesting behavior occurs during dotted access from an instance. The
1157dotted lookup calls :meth:`__get__` which returns a bound method object::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001158
1159 >>> d = D()
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001160 >>> d.f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001161 <bound method D.f of <__main__.D object at 0x00B18C90>>
1162
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001163Internally, the bound method stores the underlying function and the bound
1164instance::
1165
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001166 >>> d.f.__func__
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001167 <function D.f at 0x00C45070>
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001168
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001169 >>> d.f.__self__
1170 <__main__.D object at 0x1012e1f98>
Georg Brandl45cceeb2010-05-19 21:39:51 +00001171
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001172If you have ever wondered where *self* comes from in regular methods or where
1173*cls* comes from in class methods, this is it!
1174
Georg Brandl45cceeb2010-05-19 21:39:51 +00001175
Raymond Hettingere4c88952021-04-03 13:07:52 -07001176Kinds of methods
1177----------------
Georg Brandl45cceeb2010-05-19 21:39:51 +00001178
1179Non-data descriptors provide a simple mechanism for variations on the usual
1180patterns of binding functions into methods.
1181
1182To recap, functions have a :meth:`__get__` method so that they can be converted
Serhiy Storchakad65c9492015-11-02 14:10:23 +02001183to a method when accessed as attributes. The non-data descriptor transforms an
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001184``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``cls.f(*args)``
Georg Brandl45cceeb2010-05-19 21:39:51 +00001185becomes ``f(*args)``.
1186
1187This chart summarizes the binding and its two most useful variants:
1188
1189 +-----------------+----------------------+------------------+
1190 | Transformation | Called from an | Called from a |
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001191 | | object | class |
Georg Brandl45cceeb2010-05-19 21:39:51 +00001192 +=================+======================+==================+
1193 | function | f(obj, \*args) | f(\*args) |
1194 +-----------------+----------------------+------------------+
1195 | staticmethod | f(\*args) | f(\*args) |
1196 +-----------------+----------------------+------------------+
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001197 | classmethod | f(type(obj), \*args) | f(cls, \*args) |
Georg Brandl45cceeb2010-05-19 21:39:51 +00001198 +-----------------+----------------------+------------------+
1199
Raymond Hettingerf00e82f2021-03-13 13:46:32 -08001200
1201Static methods
1202--------------
1203
Georg Brandl45cceeb2010-05-19 21:39:51 +00001204Static methods return the underlying function without changes. Calling either
1205``c.f`` or ``C.f`` is the equivalent of a direct lookup into
1206``object.__getattribute__(c, "f")`` or ``object.__getattribute__(C, "f")``. As a
1207result, the function becomes identically accessible from either an object or a
1208class.
1209
1210Good candidates for static methods are methods that do not reference the
1211``self`` variable.
1212
1213For instance, a statistics package may include a container class for
1214experimental data. The class provides normal methods for computing the average,
1215mean, median, and other descriptive statistics that depend on the data. However,
1216there may be useful functions which are conceptually related but do not depend
1217on the data. For instance, ``erf(x)`` is handy conversion routine that comes up
1218in statistical work but does not directly depend on a particular dataset.
1219It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` or
1220``Sample.erf(1.5) --> .9332``.
1221
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001222Since static methods return the underlying function with no changes, the
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001223example calls are unexciting:
1224
1225.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001226
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001227 class E:
1228 @staticmethod
1229 def f(x):
Raymond Hettingere4c88952021-04-03 13:07:52 -07001230 return x * 10
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001231
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001232.. doctest::
1233
Shubham Aggarwalabbdd1f2019-03-20 08:25:55 +05301234 >>> E.f(3)
Raymond Hettingere4c88952021-04-03 13:07:52 -07001235 30
Shubham Aggarwalabbdd1f2019-03-20 08:25:55 +05301236 >>> E().f(3)
Raymond Hettingere4c88952021-04-03 13:07:52 -07001237 30
Georg Brandl45cceeb2010-05-19 21:39:51 +00001238
1239Using the non-data descriptor protocol, a pure Python version of
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001240:func:`staticmethod` would look like this:
1241
Raymond Hettingere4c88952021-04-03 13:07:52 -07001242.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001243
Serhiy Storchakae042a452019-06-10 13:35:52 +03001244 class StaticMethod:
Serhiy Storchakadba90392016-05-10 12:01:23 +03001245 "Emulate PyStaticMethod_Type() in Objects/funcobject.c"
Georg Brandl45cceeb2010-05-19 21:39:51 +00001246
Serhiy Storchakadba90392016-05-10 12:01:23 +03001247 def __init__(self, f):
1248 self.f = f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001249
Serhiy Storchakadba90392016-05-10 12:01:23 +03001250 def __get__(self, obj, objtype=None):
1251 return self.f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001252
Raymond Hettingere4c88952021-04-03 13:07:52 -07001253.. testcode::
1254 :hide:
1255
1256 class E_sim:
1257 @StaticMethod
1258 def f(x):
1259 return x * 10
1260
1261.. doctest::
1262 :hide:
1263
1264 >>> E_sim.f(3)
1265 30
1266 >>> E_sim().f(3)
1267 30
1268
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001269
Raymond Hettingere9208f02020-11-01 20:15:50 -08001270Class methods
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001271-------------
1272
Georg Brandl45cceeb2010-05-19 21:39:51 +00001273Unlike static methods, class methods prepend the class reference to the
1274argument list before calling the function. This format is the same
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001275for whether the caller is an object or a class:
1276
1277.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001278
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001279 class F:
1280 @classmethod
1281 def f(cls, x):
1282 return cls.__name__, x
1283
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001284.. doctest::
1285
1286 >>> F.f(3)
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001287 ('F', 3)
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001288 >>> F().f(3)
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001289 ('F', 3)
Georg Brandl45cceeb2010-05-19 21:39:51 +00001290
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001291This behavior is useful whenever the method only needs to have a class
basak9d09e172020-11-25 14:12:17 +00001292reference and does not rely on data stored in a specific instance. One use for
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001293class methods is to create alternate class constructors. For example, the
1294classmethod :func:`dict.fromkeys` creates a new dictionary from a list of
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001295keys. The pure Python equivalent is:
Georg Brandl45cceeb2010-05-19 21:39:51 +00001296
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001297.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001298
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001299 class Dict(dict):
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001300 @classmethod
1301 def fromkeys(cls, iterable, value=None):
Georg Brandl45cceeb2010-05-19 21:39:51 +00001302 "Emulate dict_fromkeys() in Objects/dictobject.c"
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001303 d = cls()
Georg Brandl45cceeb2010-05-19 21:39:51 +00001304 for key in iterable:
1305 d[key] = value
1306 return d
Georg Brandl45cceeb2010-05-19 21:39:51 +00001307
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001308Now a new dictionary of unique keys can be constructed like this:
1309
1310.. doctest::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001311
Raymond Hettinger85c84922020-11-25 01:54:24 -08001312 >>> d = Dict.fromkeys('abracadabra')
1313 >>> type(d) is Dict
1314 True
1315 >>> d
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001316 {'a': None, 'b': None, 'r': None, 'c': None, 'd': None}
Georg Brandl45cceeb2010-05-19 21:39:51 +00001317
1318Using the non-data descriptor protocol, a pure Python version of
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001319:func:`classmethod` would look like this:
1320
1321.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001322
Serhiy Storchakae042a452019-06-10 13:35:52 +03001323 class ClassMethod:
Serhiy Storchakadba90392016-05-10 12:01:23 +03001324 "Emulate PyClassMethod_Type() in Objects/funcobject.c"
Georg Brandl45cceeb2010-05-19 21:39:51 +00001325
Serhiy Storchakadba90392016-05-10 12:01:23 +03001326 def __init__(self, f):
1327 self.f = f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001328
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001329 def __get__(self, obj, cls=None):
1330 if cls is None:
1331 cls = type(obj)
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001332 if hasattr(obj, '__get__'):
1333 return self.f.__get__(cls)
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001334 return MethodType(self.f, cls)
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001335
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001336.. testcode::
1337 :hide:
1338
1339 # Verify the emulation works
1340 class T:
1341 @ClassMethod
1342 def cm(cls, x, y):
1343 return (cls, x, y)
1344
1345.. doctest::
1346 :hide:
1347
1348 >>> T.cm(11, 22)
1349 (<class 'T'>, 11, 22)
1350
1351 # Also call it from an instance
1352 >>> t = T()
1353 >>> t.cm(11, 22)
1354 (<class 'T'>, 11, 22)
1355
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001356The code path for ``hasattr(obj, '__get__')`` was added in Python 3.9 and
1357makes it possible for :func:`classmethod` to support chained decorators.
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001358For example, a classmethod and property could be chained together:
1359
1360.. testcode::
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001361
1362 class G:
1363 @classmethod
1364 @property
1365 def __doc__(cls):
1366 return f'A doc for {cls.__name__!r}'
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001367
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001368.. doctest::
1369
1370 >>> G.__doc__
1371 "A doc for 'G'"
1372
1373
Raymond Hettingere9208f02020-11-01 20:15:50 -08001374Member objects and __slots__
1375----------------------------
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001376
1377When a class defines ``__slots__``, it replaces instance dictionaries with a
1378fixed-length array of slot values. From a user point of view that has
1379several effects:
1380
13811. Provides immediate detection of bugs due to misspelled attribute
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001382assignments. Only attribute names specified in ``__slots__`` are allowed:
1383
1384.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001385
1386 class Vehicle:
1387 __slots__ = ('id_number', 'make', 'model')
1388
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001389.. doctest::
1390
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001391 >>> auto = Vehicle()
1392 >>> auto.id_nubmer = 'VYE483814LQEX'
1393 Traceback (most recent call last):
1394 ...
1395 AttributeError: 'Vehicle' object has no attribute 'id_nubmer'
1396
13972. Helps create immutable objects where descriptors manage access to private
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001398attributes stored in ``__slots__``:
1399
1400.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001401
1402 class Immutable:
1403
Raymond Hettinger80318772020-11-06 01:30:17 -08001404 __slots__ = ('_dept', '_name') # Replace the instance dictionary
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001405
1406 def __init__(self, dept, name):
1407 self._dept = dept # Store to private attribute
1408 self._name = name # Store to private attribute
1409
1410 @property # Read-only descriptor
1411 def dept(self):
1412 return self._dept
1413
1414 @property
1415 def name(self): # Read-only descriptor
1416 return self._name
1417
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001418.. doctest::
1419
1420 >>> mark = Immutable('Botany', 'Mark Watney')
1421 >>> mark.dept
1422 'Botany'
1423 >>> mark.dept = 'Space Pirate'
1424 Traceback (most recent call last):
1425 ...
1426 AttributeError: can't set attribute
1427 >>> mark.location = 'Mars'
1428 Traceback (most recent call last):
1429 ...
1430 AttributeError: 'Immutable' object has no attribute 'location'
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001431
14323. Saves memory. On a 64-bit Linux build, an instance with two attributes
1433takes 48 bytes with ``__slots__`` and 152 bytes without. This `flyweight
1434design pattern <https://en.wikipedia.org/wiki/Flyweight_pattern>`_ likely only
1435matters when a large number of instances are going to be created.
1436
Raymond Hettinger755c6e62021-02-04 22:05:42 -080014374. Improves speed. Reading instance variables is 35% faster with
1438``__slots__`` (as measured with Python 3.10 on an Apple M1 processor).
1439
14405. Blocks tools like :func:`functools.cached_property` which require an
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001441instance dictionary to function correctly:
1442
1443.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001444
1445 from functools import cached_property
1446
1447 class CP:
1448 __slots__ = () # Eliminates the instance dict
1449
1450 @cached_property # Requires an instance dict
1451 def pi(self):
1452 return 4 * sum((-1.0)**n / (2.0*n + 1.0)
1453 for n in reversed(range(100_000)))
1454
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001455.. doctest::
1456
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001457 >>> CP().pi
1458 Traceback (most recent call last):
1459 ...
1460 TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property.
1461
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001462It is not possible to create an exact drop-in pure Python version of
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001463``__slots__`` because it requires direct access to C structures and control
1464over object memory allocation. However, we can build a mostly faithful
1465simulation where the actual C structure for slots is emulated by a private
1466``_slotvalues`` list. Reads and writes to that private structure are managed
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001467by member descriptors:
1468
1469.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001470
Raymond Hettingerffae9322020-11-23 10:56:59 -08001471 null = object()
1472
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001473 class Member:
1474
1475 def __init__(self, name, clsname, offset):
1476 'Emulate PyMemberDef in Include/structmember.h'
1477 # Also see descr_new() in Objects/descrobject.c
1478 self.name = name
1479 self.clsname = clsname
1480 self.offset = offset
1481
1482 def __get__(self, obj, objtype=None):
1483 'Emulate member_get() in Objects/descrobject.c'
1484 # Also see PyMember_GetOne() in Python/structmember.c
Raymond Hettingerffae9322020-11-23 10:56:59 -08001485 value = obj._slotvalues[self.offset]
1486 if value is null:
1487 raise AttributeError(self.name)
1488 return value
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001489
1490 def __set__(self, obj, value):
1491 'Emulate member_set() in Objects/descrobject.c'
1492 obj._slotvalues[self.offset] = value
1493
Raymond Hettingerffae9322020-11-23 10:56:59 -08001494 def __delete__(self, obj):
1495 'Emulate member_delete() in Objects/descrobject.c'
1496 value = obj._slotvalues[self.offset]
1497 if value is null:
1498 raise AttributeError(self.name)
1499 obj._slotvalues[self.offset] = null
1500
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001501 def __repr__(self):
1502 'Emulate member_repr() in Objects/descrobject.c'
1503 return f'<Member {self.name!r} of {self.clsname!r}>'
1504
1505The :meth:`type.__new__` method takes care of adding member objects to class
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001506variables:
1507
1508.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001509
1510 class Type(type):
1511 'Simulate how the type metaclass adds member objects for slots'
1512
1513 def __new__(mcls, clsname, bases, mapping):
1514 'Emuluate type_new() in Objects/typeobject.c'
1515 # type_new() calls PyTypeReady() which calls add_methods()
1516 slot_names = mapping.get('slot_names', [])
1517 for offset, name in enumerate(slot_names):
1518 mapping[name] = Member(name, clsname, offset)
1519 return type.__new__(mcls, clsname, bases, mapping)
1520
Raymond Hettingerffae9322020-11-23 10:56:59 -08001521The :meth:`object.__new__` method takes care of creating instances that have
1522slots instead of an instance dictionary. Here is a rough simulation in pure
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001523Python:
1524
1525.. testcode::
Raymond Hettingerffae9322020-11-23 10:56:59 -08001526
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001527 class Object:
1528 'Simulate how object.__new__() allocates memory for __slots__'
1529
1530 def __new__(cls, *args):
1531 'Emulate object_new() in Objects/typeobject.c'
1532 inst = super().__new__(cls)
1533 if hasattr(cls, 'slot_names'):
Raymond Hettingerffae9322020-11-23 10:56:59 -08001534 empty_slots = [null] * len(cls.slot_names)
1535 object.__setattr__(inst, '_slotvalues', empty_slots)
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001536 return inst
1537
Raymond Hettingerffae9322020-11-23 10:56:59 -08001538 def __setattr__(self, name, value):
1539 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1540 cls = type(self)
1541 if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1542 raise AttributeError(
1543 f'{type(self).__name__!r} object has no attribute {name!r}'
1544 )
1545 super().__setattr__(name, value)
1546
1547 def __delattr__(self, name):
1548 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1549 cls = type(self)
1550 if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1551 raise AttributeError(
1552 f'{type(self).__name__!r} object has no attribute {name!r}'
1553 )
1554 super().__delattr__(name)
1555
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001556To use the simulation in a real class, just inherit from :class:`Object` and
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001557set the :term:`metaclass` to :class:`Type`:
1558
1559.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001560
1561 class H(Object, metaclass=Type):
Raymond Hettingerffae9322020-11-23 10:56:59 -08001562 'Instance variables stored in slots'
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001563
1564 slot_names = ['x', 'y']
1565
1566 def __init__(self, x, y):
1567 self.x = x
1568 self.y = y
1569
1570At this point, the metaclass has loaded member objects for *x* and *y*::
1571
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001572 >>> from pprint import pp
1573 >>> pp(dict(vars(H)))
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001574 {'__module__': '__main__',
Raymond Hettingerffae9322020-11-23 10:56:59 -08001575 '__doc__': 'Instance variables stored in slots',
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001576 'slot_names': ['x', 'y'],
1577 '__init__': <function H.__init__ at 0x7fb5d302f9d0>,
1578 'x': <Member 'x' of 'H'>,
Raymond Hettingerffae9322020-11-23 10:56:59 -08001579 'y': <Member 'y' of 'H'>}
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001580
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001581.. doctest::
1582 :hide:
1583
1584 # We test this separately because the preceding section is not
1585 # doctestable due to the hex memory address for the __init__ function
1586 >>> isinstance(vars(H)['x'], Member)
1587 True
1588 >>> isinstance(vars(H)['y'], Member)
1589 True
1590
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001591When instances are created, they have a ``slot_values`` list where the
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001592attributes are stored:
1593
1594.. doctest::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001595
1596 >>> h = H(10, 20)
1597 >>> vars(h)
1598 {'_slotvalues': [10, 20]}
1599 >>> h.x = 55
1600 >>> vars(h)
1601 {'_slotvalues': [55, 20]}
1602
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001603Misspelled or unassigned attributes will raise an exception:
1604
1605.. doctest::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001606
Raymond Hettingerffae9322020-11-23 10:56:59 -08001607 >>> h.xz
1608 Traceback (most recent call last):
1609 ...
1610 AttributeError: 'H' object has no attribute 'xz'
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001611
1612.. doctest::
1613 :hide:
1614
1615 # Examples for deleted attributes are not shown because this section
1616 # is already a bit lengthy. We still test that code here.
1617 >>> del h.x
1618 >>> hasattr(h, 'x')
1619 False
1620
1621 # Also test the code for uninitialized slots
1622 >>> class HU(Object, metaclass=Type):
1623 ... slot_names = ['x', 'y']
1624 ...
1625 >>> hu = HU()
1626 >>> hasattr(hu, 'x')
1627 False
1628 >>> hasattr(hu, 'y')
1629 False