blob: 575caeb720f3d0fa6f84580e7a449f768d50abe2 [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
Raymond Hettingerfe240882021-04-22 20:02:46 -0700956.. doctest::
957 :hide:
958
959 >>> C.x.__doc__
960 "I'm the 'x' property."
961 >>> c.x = 2.71828
962 >>> c.x
963 2.71828
964 >>> del c.x
965 >>> c.x
966 Traceback (most recent call last):
967 ...
968 AttributeError: 'C' object has no attribute '_C__x'
969
Georg Brandl45cceeb2010-05-19 21:39:51 +0000970To see how :func:`property` is implemented in terms of the descriptor protocol,
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -0800971here is a pure Python equivalent:
972
973.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +0000974
Serhiy Storchakae042a452019-06-10 13:35:52 +0300975 class Property:
Georg Brandl45cceeb2010-05-19 21:39:51 +0000976 "Emulate PyProperty_Type() in Objects/descrobject.c"
977
978 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
979 self.fget = fget
980 self.fset = fset
981 self.fdel = fdel
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700982 if doc is None and fget is not None:
983 doc = fget.__doc__
Georg Brandl45cceeb2010-05-19 21:39:51 +0000984 self.__doc__ = doc
Yurii Karabasc56387f2020-12-30 11:51:24 +0200985 self._name = ''
986
987 def __set_name__(self, owner, name):
988 self._name = name
Georg Brandl45cceeb2010-05-19 21:39:51 +0000989
990 def __get__(self, obj, objtype=None):
991 if obj is None:
992 return self
993 if self.fget is None:
Yurii Karabasc56387f2020-12-30 11:51:24 +0200994 raise AttributeError(f'unreadable attribute {self._name}')
Georg Brandl45cceeb2010-05-19 21:39:51 +0000995 return self.fget(obj)
996
997 def __set__(self, obj, value):
998 if self.fset is None:
Yurii Karabasc56387f2020-12-30 11:51:24 +0200999 raise AttributeError(f"can't set attribute {self._name}")
Georg Brandl45cceeb2010-05-19 21:39:51 +00001000 self.fset(obj, value)
1001
1002 def __delete__(self, obj):
1003 if self.fdel is None:
Yurii Karabasc56387f2020-12-30 11:51:24 +02001004 raise AttributeError(f"can't delete attribute {self._name}")
Georg Brandl45cceeb2010-05-19 21:39:51 +00001005 self.fdel(obj)
1006
Raymond Hettinger632c8c82013-03-10 09:41:18 -07001007 def getter(self, fget):
Yurii Karabasc56387f2020-12-30 11:51:24 +02001008 prop = type(self)(fget, self.fset, self.fdel, self.__doc__)
1009 prop._name = self._name
1010 return prop
Raymond Hettinger632c8c82013-03-10 09:41:18 -07001011
1012 def setter(self, fset):
Yurii Karabasc56387f2020-12-30 11:51:24 +02001013 prop = type(self)(self.fget, fset, self.fdel, self.__doc__)
1014 prop._name = self._name
1015 return prop
Raymond Hettinger632c8c82013-03-10 09:41:18 -07001016
1017 def deleter(self, fdel):
Yurii Karabasc56387f2020-12-30 11:51:24 +02001018 prop = type(self)(self.fget, self.fset, fdel, self.__doc__)
1019 prop._name = self._name
1020 return prop
Raymond Hettinger632c8c82013-03-10 09:41:18 -07001021
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001022.. testcode::
1023 :hide:
1024
1025 # Verify the Property() emulation
1026
1027 class CC:
1028 def getx(self):
1029 return self.__x
1030 def setx(self, value):
1031 self.__x = value
1032 def delx(self):
1033 del self.__x
1034 x = Property(getx, setx, delx, "I'm the 'x' property.")
1035
1036 # Now do it again but use the decorator style
1037
1038 class CCC:
1039 @Property
1040 def x(self):
1041 return self.__x
1042 @x.setter
1043 def x(self, value):
1044 self.__x = value
1045 @x.deleter
1046 def x(self):
1047 del self.__x
1048
1049
1050.. doctest::
1051 :hide:
1052
1053 >>> cc = CC()
1054 >>> hasattr(cc, 'x')
1055 False
1056 >>> cc.x = 33
1057 >>> cc.x
1058 33
1059 >>> del cc.x
1060 >>> hasattr(cc, 'x')
1061 False
1062
1063 >>> ccc = CCC()
1064 >>> hasattr(ccc, 'x')
1065 False
1066 >>> ccc.x = 333
1067 >>> ccc.x == 333
1068 True
1069 >>> del ccc.x
1070 >>> hasattr(ccc, 'x')
1071 False
1072
Georg Brandl45cceeb2010-05-19 21:39:51 +00001073The :func:`property` builtin helps whenever a user interface has granted
1074attribute access and then subsequent changes require the intervention of a
1075method.
1076
1077For instance, a spreadsheet class may grant access to a cell value through
1078``Cell('b10').value``. Subsequent improvements to the program require the cell
1079to be recalculated on every access; however, the programmer does not want to
1080affect existing client code accessing the attribute directly. The solution is
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001081to wrap access to the value attribute in a property data descriptor:
1082
1083.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001084
Serhiy Storchakae042a452019-06-10 13:35:52 +03001085 class Cell:
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001086 ...
1087
1088 @property
1089 def value(self):
_ = NaNb066edf2017-06-23 11:54:35 +08001090 "Recalculate the cell before returning value"
Georg Brandl45cceeb2010-05-19 21:39:51 +00001091 self.recalc()
_ = NaNb066edf2017-06-23 11:54:35 +08001092 return self._value
Georg Brandl45cceeb2010-05-19 21:39:51 +00001093
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001094Either the built-in :func:`property` or our :func:`Property` equivalent would
1095work in this example.
1096
Georg Brandl45cceeb2010-05-19 21:39:51 +00001097
Raymond Hettingere9208f02020-11-01 20:15:50 -08001098Functions and methods
Georg Brandl45cceeb2010-05-19 21:39:51 +00001099---------------------
1100
1101Python's object oriented features are built upon a function based environment.
1102Using non-data descriptors, the two are merged seamlessly.
1103
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001104Functions stored in class dictionaries get turned into methods when invoked.
1105Methods only differ from regular functions in that the object instance is
1106prepended to the other arguments. By convention, the instance is called
1107*self* but could be called *this* or any other variable name.
Georg Brandl45cceeb2010-05-19 21:39:51 +00001108
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001109Methods can be created manually with :class:`types.MethodType` which is
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001110roughly equivalent to:
1111
1112.. testcode::
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001113
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001114 class MethodType:
Zackery Spytze689cdc2021-04-01 11:03:33 -06001115 "Emulate PyMethod_Type in Objects/classobject.c"
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001116
1117 def __init__(self, func, obj):
1118 self.__func__ = func
1119 self.__self__ = obj
1120
1121 def __call__(self, *args, **kwargs):
1122 func = self.__func__
1123 obj = self.__self__
1124 return func(obj, *args, **kwargs)
1125
1126To support automatic creation of methods, functions include the
1127:meth:`__get__` method for binding methods during attribute access. This
Raymond Hettinger80318772020-11-06 01:30:17 -08001128means that functions are non-data descriptors that return bound methods
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001129during dotted lookup from an instance. Here's how it works:
1130
1131.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001132
Serhiy Storchakae042a452019-06-10 13:35:52 +03001133 class Function:
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001134 ...
1135
Georg Brandl45cceeb2010-05-19 21:39:51 +00001136 def __get__(self, obj, objtype=None):
1137 "Simulate func_descr_get() in Objects/funcobject.c"
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001138 if obj is None:
1139 return self
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001140 return MethodType(self, obj)
Georg Brandl45cceeb2010-05-19 21:39:51 +00001141
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001142Running the following class in the interpreter shows how the function
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001143descriptor works in practice:
1144
1145.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001146
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001147 class D:
1148 def f(self, x):
1149 return x
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001150
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001151The function has a :term:`qualified name` attribute to support introspection:
1152
1153.. doctest::
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001154
1155 >>> D.f.__qualname__
1156 'D.f'
1157
1158Accessing the function through the class dictionary does not invoke
1159:meth:`__get__`. Instead, it just returns the underlying function object::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001160
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001161 >>> D.__dict__['f']
1162 <function D.f at 0x00C45070>
1163
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001164Dotted access from a class calls :meth:`__get__` which just returns the
1165underlying function unchanged::
1166
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001167 >>> D.f
1168 <function D.f at 0x00C45070>
1169
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001170The interesting behavior occurs during dotted access from an instance. The
1171dotted lookup calls :meth:`__get__` which returns a bound method object::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001172
1173 >>> d = D()
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001174 >>> d.f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001175 <bound method D.f of <__main__.D object at 0x00B18C90>>
1176
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001177Internally, the bound method stores the underlying function and the bound
1178instance::
1179
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001180 >>> d.f.__func__
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001181 <function D.f at 0x00C45070>
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001182
Raymond Hettinger0d4497b2017-09-25 01:05:49 -07001183 >>> d.f.__self__
1184 <__main__.D object at 0x1012e1f98>
Georg Brandl45cceeb2010-05-19 21:39:51 +00001185
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001186If you have ever wondered where *self* comes from in regular methods or where
1187*cls* comes from in class methods, this is it!
1188
Georg Brandl45cceeb2010-05-19 21:39:51 +00001189
Raymond Hettingere4c88952021-04-03 13:07:52 -07001190Kinds of methods
1191----------------
Georg Brandl45cceeb2010-05-19 21:39:51 +00001192
1193Non-data descriptors provide a simple mechanism for variations on the usual
1194patterns of binding functions into methods.
1195
1196To recap, functions have a :meth:`__get__` method so that they can be converted
Serhiy Storchakad65c9492015-11-02 14:10:23 +02001197to a method when accessed as attributes. The non-data descriptor transforms an
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001198``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``cls.f(*args)``
Georg Brandl45cceeb2010-05-19 21:39:51 +00001199becomes ``f(*args)``.
1200
1201This chart summarizes the binding and its two most useful variants:
1202
1203 +-----------------+----------------------+------------------+
1204 | Transformation | Called from an | Called from a |
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001205 | | object | class |
Georg Brandl45cceeb2010-05-19 21:39:51 +00001206 +=================+======================+==================+
1207 | function | f(obj, \*args) | f(\*args) |
1208 +-----------------+----------------------+------------------+
1209 | staticmethod | f(\*args) | f(\*args) |
1210 +-----------------+----------------------+------------------+
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001211 | classmethod | f(type(obj), \*args) | f(cls, \*args) |
Georg Brandl45cceeb2010-05-19 21:39:51 +00001212 +-----------------+----------------------+------------------+
1213
Raymond Hettingerf00e82f2021-03-13 13:46:32 -08001214
1215Static methods
1216--------------
1217
Georg Brandl45cceeb2010-05-19 21:39:51 +00001218Static methods return the underlying function without changes. Calling either
1219``c.f`` or ``C.f`` is the equivalent of a direct lookup into
1220``object.__getattribute__(c, "f")`` or ``object.__getattribute__(C, "f")``. As a
1221result, the function becomes identically accessible from either an object or a
1222class.
1223
1224Good candidates for static methods are methods that do not reference the
1225``self`` variable.
1226
1227For instance, a statistics package may include a container class for
1228experimental data. The class provides normal methods for computing the average,
1229mean, median, and other descriptive statistics that depend on the data. However,
1230there may be useful functions which are conceptually related but do not depend
1231on the data. For instance, ``erf(x)`` is handy conversion routine that comes up
1232in statistical work but does not directly depend on a particular dataset.
1233It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` or
1234``Sample.erf(1.5) --> .9332``.
1235
Raymond Hettinger4a9c6372020-10-24 20:34:39 -07001236Since static methods return the underlying function with no changes, the
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001237example calls are unexciting:
1238
1239.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001240
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001241 class E:
1242 @staticmethod
1243 def f(x):
Raymond Hettingere4c88952021-04-03 13:07:52 -07001244 return x * 10
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001245
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001246.. doctest::
1247
Shubham Aggarwalabbdd1f2019-03-20 08:25:55 +05301248 >>> E.f(3)
Raymond Hettingere4c88952021-04-03 13:07:52 -07001249 30
Shubham Aggarwalabbdd1f2019-03-20 08:25:55 +05301250 >>> E().f(3)
Raymond Hettingere4c88952021-04-03 13:07:52 -07001251 30
Georg Brandl45cceeb2010-05-19 21:39:51 +00001252
1253Using the non-data descriptor protocol, a pure Python version of
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001254:func:`staticmethod` would look like this:
1255
Raymond Hettingere4c88952021-04-03 13:07:52 -07001256.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001257
Serhiy Storchakae042a452019-06-10 13:35:52 +03001258 class StaticMethod:
Serhiy Storchakadba90392016-05-10 12:01:23 +03001259 "Emulate PyStaticMethod_Type() in Objects/funcobject.c"
Georg Brandl45cceeb2010-05-19 21:39:51 +00001260
Serhiy Storchakadba90392016-05-10 12:01:23 +03001261 def __init__(self, f):
1262 self.f = f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001263
Serhiy Storchakadba90392016-05-10 12:01:23 +03001264 def __get__(self, obj, objtype=None):
1265 return self.f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001266
Raymond Hettingere4c88952021-04-03 13:07:52 -07001267.. testcode::
1268 :hide:
1269
1270 class E_sim:
1271 @StaticMethod
1272 def f(x):
1273 return x * 10
1274
1275.. doctest::
1276 :hide:
1277
1278 >>> E_sim.f(3)
1279 30
1280 >>> E_sim().f(3)
1281 30
1282
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001283
Raymond Hettingere9208f02020-11-01 20:15:50 -08001284Class methods
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001285-------------
1286
Georg Brandl45cceeb2010-05-19 21:39:51 +00001287Unlike static methods, class methods prepend the class reference to the
1288argument list before calling the function. This format is the same
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001289for whether the caller is an object or a class:
1290
1291.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001292
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001293 class F:
1294 @classmethod
1295 def f(cls, x):
1296 return cls.__name__, x
1297
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001298.. doctest::
1299
1300 >>> F.f(3)
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001301 ('F', 3)
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001302 >>> F().f(3)
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001303 ('F', 3)
Georg Brandl45cceeb2010-05-19 21:39:51 +00001304
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001305This behavior is useful whenever the method only needs to have a class
basak9d09e172020-11-25 14:12:17 +00001306reference and does not rely on data stored in a specific instance. One use for
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001307class methods is to create alternate class constructors. For example, the
1308classmethod :func:`dict.fromkeys` creates a new dictionary from a list of
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001309keys. The pure Python equivalent is:
Georg Brandl45cceeb2010-05-19 21:39:51 +00001310
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001311.. testcode::
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001312
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001313 class Dict(dict):
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001314 @classmethod
1315 def fromkeys(cls, iterable, value=None):
Georg Brandl45cceeb2010-05-19 21:39:51 +00001316 "Emulate dict_fromkeys() in Objects/dictobject.c"
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001317 d = cls()
Georg Brandl45cceeb2010-05-19 21:39:51 +00001318 for key in iterable:
1319 d[key] = value
1320 return d
Georg Brandl45cceeb2010-05-19 21:39:51 +00001321
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001322Now a new dictionary of unique keys can be constructed like this:
1323
1324.. doctest::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001325
Raymond Hettinger85c84922020-11-25 01:54:24 -08001326 >>> d = Dict.fromkeys('abracadabra')
1327 >>> type(d) is Dict
1328 True
1329 >>> d
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001330 {'a': None, 'b': None, 'r': None, 'c': None, 'd': None}
Georg Brandl45cceeb2010-05-19 21:39:51 +00001331
1332Using the non-data descriptor protocol, a pure Python version of
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001333:func:`classmethod` would look like this:
1334
1335.. testcode::
Georg Brandl45cceeb2010-05-19 21:39:51 +00001336
Serhiy Storchakae042a452019-06-10 13:35:52 +03001337 class ClassMethod:
Serhiy Storchakadba90392016-05-10 12:01:23 +03001338 "Emulate PyClassMethod_Type() in Objects/funcobject.c"
Georg Brandl45cceeb2010-05-19 21:39:51 +00001339
Serhiy Storchakadba90392016-05-10 12:01:23 +03001340 def __init__(self, f):
1341 self.f = f
Georg Brandl45cceeb2010-05-19 21:39:51 +00001342
Raymond Hettinger8d3d7312020-10-23 12:55:39 -07001343 def __get__(self, obj, cls=None):
1344 if cls is None:
1345 cls = type(obj)
Raymond Hettinger14092b52021-04-22 17:53:36 -07001346 if hasattr(type(self.f), '__get__'):
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001347 return self.f.__get__(cls)
Raymond Hettingere6a7ea42020-10-25 07:12:50 -07001348 return MethodType(self.f, cls)
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001349
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001350.. testcode::
1351 :hide:
1352
1353 # Verify the emulation works
1354 class T:
1355 @ClassMethod
1356 def cm(cls, x, y):
1357 return (cls, x, y)
1358
Raymond Hettinger14092b52021-04-22 17:53:36 -07001359 @ClassMethod
1360 @property
1361 def __doc__(cls):
1362 return f'A doc for {cls.__name__!r}'
1363
1364
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001365.. doctest::
1366 :hide:
1367
1368 >>> T.cm(11, 22)
1369 (<class 'T'>, 11, 22)
1370
1371 # Also call it from an instance
1372 >>> t = T()
1373 >>> t.cm(11, 22)
1374 (<class 'T'>, 11, 22)
1375
Raymond Hettinger14092b52021-04-22 17:53:36 -07001376 # Check the alternate path for chained descriptors
1377 >>> T.__doc__
1378 "A doc for 'T'"
1379
1380
Raymond Hettingerfe240882021-04-22 20:02:46 -07001381The code path for ``hasattr(type(self.f), '__get__')`` was added in
1382Python 3.9 and makes it possible for :func:`classmethod` to support
1383chained decorators. For example, a classmethod and property could be
1384chained together:
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001385
1386.. testcode::
Raymond Hettinger8e5b0fd2020-10-23 18:37:27 -07001387
1388 class G:
1389 @classmethod
1390 @property
1391 def __doc__(cls):
1392 return f'A doc for {cls.__name__!r}'
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001393
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001394.. doctest::
1395
1396 >>> G.__doc__
1397 "A doc for 'G'"
1398
1399
Raymond Hettingere9208f02020-11-01 20:15:50 -08001400Member objects and __slots__
1401----------------------------
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001402
1403When a class defines ``__slots__``, it replaces instance dictionaries with a
1404fixed-length array of slot values. From a user point of view that has
1405several effects:
1406
14071. Provides immediate detection of bugs due to misspelled attribute
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001408assignments. Only attribute names specified in ``__slots__`` are allowed:
1409
1410.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001411
1412 class Vehicle:
1413 __slots__ = ('id_number', 'make', 'model')
1414
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001415.. doctest::
1416
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001417 >>> auto = Vehicle()
1418 >>> auto.id_nubmer = 'VYE483814LQEX'
1419 Traceback (most recent call last):
1420 ...
1421 AttributeError: 'Vehicle' object has no attribute 'id_nubmer'
1422
14232. Helps create immutable objects where descriptors manage access to private
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001424attributes stored in ``__slots__``:
1425
1426.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001427
1428 class Immutable:
1429
Raymond Hettinger80318772020-11-06 01:30:17 -08001430 __slots__ = ('_dept', '_name') # Replace the instance dictionary
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001431
1432 def __init__(self, dept, name):
1433 self._dept = dept # Store to private attribute
1434 self._name = name # Store to private attribute
1435
1436 @property # Read-only descriptor
1437 def dept(self):
1438 return self._dept
1439
1440 @property
1441 def name(self): # Read-only descriptor
1442 return self._name
1443
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001444.. doctest::
1445
1446 >>> mark = Immutable('Botany', 'Mark Watney')
1447 >>> mark.dept
1448 'Botany'
1449 >>> mark.dept = 'Space Pirate'
1450 Traceback (most recent call last):
1451 ...
1452 AttributeError: can't set attribute
1453 >>> mark.location = 'Mars'
1454 Traceback (most recent call last):
1455 ...
1456 AttributeError: 'Immutable' object has no attribute 'location'
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001457
14583. Saves memory. On a 64-bit Linux build, an instance with two attributes
1459takes 48 bytes with ``__slots__`` and 152 bytes without. This `flyweight
1460design pattern <https://en.wikipedia.org/wiki/Flyweight_pattern>`_ likely only
1461matters when a large number of instances are going to be created.
1462
Raymond Hettinger755c6e62021-02-04 22:05:42 -080014634. Improves speed. Reading instance variables is 35% faster with
1464``__slots__`` (as measured with Python 3.10 on an Apple M1 processor).
1465
14665. Blocks tools like :func:`functools.cached_property` which require an
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001467instance dictionary to function correctly:
1468
1469.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001470
1471 from functools import cached_property
1472
1473 class CP:
1474 __slots__ = () # Eliminates the instance dict
1475
1476 @cached_property # Requires an instance dict
1477 def pi(self):
1478 return 4 * sum((-1.0)**n / (2.0*n + 1.0)
1479 for n in reversed(range(100_000)))
1480
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001481.. doctest::
1482
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001483 >>> CP().pi
1484 Traceback (most recent call last):
1485 ...
1486 TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property.
1487
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001488It is not possible to create an exact drop-in pure Python version of
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001489``__slots__`` because it requires direct access to C structures and control
1490over object memory allocation. However, we can build a mostly faithful
1491simulation where the actual C structure for slots is emulated by a private
1492``_slotvalues`` list. Reads and writes to that private structure are managed
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001493by member descriptors:
1494
1495.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001496
Raymond Hettingerffae9322020-11-23 10:56:59 -08001497 null = object()
1498
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001499 class Member:
1500
1501 def __init__(self, name, clsname, offset):
1502 'Emulate PyMemberDef in Include/structmember.h'
1503 # Also see descr_new() in Objects/descrobject.c
1504 self.name = name
1505 self.clsname = clsname
1506 self.offset = offset
1507
1508 def __get__(self, obj, objtype=None):
1509 'Emulate member_get() in Objects/descrobject.c'
1510 # Also see PyMember_GetOne() in Python/structmember.c
Raymond Hettingerffae9322020-11-23 10:56:59 -08001511 value = obj._slotvalues[self.offset]
1512 if value is null:
1513 raise AttributeError(self.name)
1514 return value
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001515
1516 def __set__(self, obj, value):
1517 'Emulate member_set() in Objects/descrobject.c'
1518 obj._slotvalues[self.offset] = value
1519
Raymond Hettingerffae9322020-11-23 10:56:59 -08001520 def __delete__(self, obj):
1521 'Emulate member_delete() in Objects/descrobject.c'
1522 value = obj._slotvalues[self.offset]
1523 if value is null:
1524 raise AttributeError(self.name)
1525 obj._slotvalues[self.offset] = null
1526
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001527 def __repr__(self):
1528 'Emulate member_repr() in Objects/descrobject.c'
1529 return f'<Member {self.name!r} of {self.clsname!r}>'
1530
1531The :meth:`type.__new__` method takes care of adding member objects to class
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001532variables:
1533
1534.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001535
1536 class Type(type):
1537 'Simulate how the type metaclass adds member objects for slots'
1538
1539 def __new__(mcls, clsname, bases, mapping):
1540 'Emuluate type_new() in Objects/typeobject.c'
1541 # type_new() calls PyTypeReady() which calls add_methods()
1542 slot_names = mapping.get('slot_names', [])
1543 for offset, name in enumerate(slot_names):
1544 mapping[name] = Member(name, clsname, offset)
1545 return type.__new__(mcls, clsname, bases, mapping)
1546
Raymond Hettingerffae9322020-11-23 10:56:59 -08001547The :meth:`object.__new__` method takes care of creating instances that have
1548slots instead of an instance dictionary. Here is a rough simulation in pure
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001549Python:
1550
1551.. testcode::
Raymond Hettingerffae9322020-11-23 10:56:59 -08001552
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001553 class Object:
1554 'Simulate how object.__new__() allocates memory for __slots__'
1555
1556 def __new__(cls, *args):
1557 'Emulate object_new() in Objects/typeobject.c'
1558 inst = super().__new__(cls)
1559 if hasattr(cls, 'slot_names'):
Raymond Hettingerffae9322020-11-23 10:56:59 -08001560 empty_slots = [null] * len(cls.slot_names)
1561 object.__setattr__(inst, '_slotvalues', empty_slots)
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001562 return inst
1563
Raymond Hettingerffae9322020-11-23 10:56:59 -08001564 def __setattr__(self, name, value):
1565 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1566 cls = type(self)
1567 if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1568 raise AttributeError(
1569 f'{type(self).__name__!r} object has no attribute {name!r}'
1570 )
1571 super().__setattr__(name, value)
1572
1573 def __delattr__(self, name):
1574 'Emulate _PyObject_GenericSetAttrWithDict() Objects/object.c'
1575 cls = type(self)
1576 if hasattr(cls, 'slot_names') and name not in cls.slot_names:
1577 raise AttributeError(
1578 f'{type(self).__name__!r} object has no attribute {name!r}'
1579 )
1580 super().__delattr__(name)
1581
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001582To use the simulation in a real class, just inherit from :class:`Object` and
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001583set the :term:`metaclass` to :class:`Type`:
1584
1585.. testcode::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001586
1587 class H(Object, metaclass=Type):
Raymond Hettingerffae9322020-11-23 10:56:59 -08001588 'Instance variables stored in slots'
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001589
1590 slot_names = ['x', 'y']
1591
1592 def __init__(self, x, y):
1593 self.x = x
1594 self.y = y
1595
1596At this point, the metaclass has loaded member objects for *x* and *y*::
1597
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001598 >>> from pprint import pp
1599 >>> pp(dict(vars(H)))
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001600 {'__module__': '__main__',
Raymond Hettingerffae9322020-11-23 10:56:59 -08001601 '__doc__': 'Instance variables stored in slots',
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001602 'slot_names': ['x', 'y'],
1603 '__init__': <function H.__init__ at 0x7fb5d302f9d0>,
1604 'x': <Member 'x' of 'H'>,
Raymond Hettingerffae9322020-11-23 10:56:59 -08001605 'y': <Member 'y' of 'H'>}
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001606
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001607.. doctest::
1608 :hide:
1609
1610 # We test this separately because the preceding section is not
1611 # doctestable due to the hex memory address for the __init__ function
1612 >>> isinstance(vars(H)['x'], Member)
1613 True
1614 >>> isinstance(vars(H)['y'], Member)
1615 True
1616
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001617When instances are created, they have a ``slot_values`` list where the
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001618attributes are stored:
1619
1620.. doctest::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001621
1622 >>> h = H(10, 20)
1623 >>> vars(h)
1624 {'_slotvalues': [10, 20]}
1625 >>> h.x = 55
1626 >>> vars(h)
1627 {'_slotvalues': [55, 20]}
1628
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001629Misspelled or unassigned attributes will raise an exception:
1630
1631.. doctest::
Raymond Hettinger74fa4642020-11-01 18:02:37 -08001632
Raymond Hettingerffae9322020-11-23 10:56:59 -08001633 >>> h.xz
1634 Traceback (most recent call last):
1635 ...
1636 AttributeError: 'H' object has no attribute 'xz'
Raymond Hettinger2d44a6b2020-11-24 20:57:02 -08001637
1638.. doctest::
1639 :hide:
1640
1641 # Examples for deleted attributes are not shown because this section
1642 # is already a bit lengthy. We still test that code here.
1643 >>> del h.x
1644 >>> hasattr(h, 'x')
1645 False
1646
1647 # Also test the code for uninitialized slots
1648 >>> class HU(Object, metaclass=Type):
1649 ... slot_names = ['x', 'y']
1650 ...
1651 >>> hu = HU()
1652 >>> hasattr(hu, 'x')
1653 False
1654 >>> hasattr(hu, 'y')
1655 False