blob: 4a77052afb1fc0eccd5116718f1fa9a7d16c8df0 [file] [log] [blame]
Georg Brandl45cceeb2010-05-19 21:39:51 +00001======================
2Descriptor HowTo Guide
3======================
4
5:Author: Raymond Hettinger
6:Contact: <python at rcn dot com>
7
8.. Contents::
9
10Abstract
11--------
12
13Defines descriptors, summarizes the protocol, and shows how descriptors are
14called. Examines a custom descriptor and several built-in python descriptors
15including functions, properties, static methods, and class methods. Shows how
16each works by giving a pure Python equivalent and a sample application.
17
18Learning about descriptors not only provides access to a larger toolset, it
19creates a deeper understanding of how Python works and an appreciation for the
20elegance of its design.
21
22
23Definition and Introduction
24---------------------------
25
26In general, a descriptor is an object attribute with "binding behavior", one
27whose attribute access has been overridden by methods in the descriptor
28protocol. Those methods are :meth:`__get__`, :meth:`__set__`, and
29:meth:`__delete__`. If any of those methods are defined for an object, it is
30said to be a descriptor.
31
32The default behavior for attribute access is to get, set, or delete the
33attribute from an object's dictionary. For instance, ``a.x`` has a lookup chain
34starting with ``a.__dict__['x']``, then ``type(a).__dict__['x']``, and
35continuing through the base classes of ``type(a)`` excluding metaclasses. If the
36looked-up value is an object defining one of the descriptor methods, then Python
37may override the default behavior and invoke the descriptor method instead.
38Where this occurs in the precedence chain depends on which descriptor methods
Florent Xiclunaaa6c1d22011-12-12 18:54:29 +010039were defined.
Georg Brandl45cceeb2010-05-19 21:39:51 +000040
41Descriptors are a powerful, general purpose protocol. They are the mechanism
42behind properties, methods, static methods, class methods, and :func:`super()`.
Ezio Melotti222e61e2011-07-31 22:49:18 +030043They are used throughout Python itself to implement the new style classes
Georg Brandl45cceeb2010-05-19 21:39:51 +000044introduced in version 2.2. Descriptors simplify the underlying C-code and offer
45a flexible set of new tools for everyday Python programs.
46
47
48Descriptor Protocol
49-------------------
50
51``descr.__get__(self, obj, type=None) --> value``
52
53``descr.__set__(self, obj, value) --> None``
54
55``descr.__delete__(self, obj) --> None``
56
57That is all there is to it. Define any of these methods and an object is
58considered a descriptor and can override default behavior upon being looked up
59as an attribute.
60
61If an object defines both :meth:`__get__` and :meth:`__set__`, it is considered
62a data descriptor. Descriptors that only define :meth:`__get__` are called
63non-data descriptors (they are typically used for methods but other uses are
64possible).
65
66Data and non-data descriptors differ in how overrides are calculated with
67respect to entries in an instance's dictionary. If an instance's dictionary
68has an entry with the same name as a data descriptor, the data descriptor
69takes precedence. If an instance's dictionary has an entry with the same
70name as a non-data descriptor, the dictionary entry takes precedence.
71
72To make a read-only data descriptor, define both :meth:`__get__` and
73:meth:`__set__` with the :meth:`__set__` raising an :exc:`AttributeError` when
74called. Defining the :meth:`__set__` method with an exception raising
75placeholder is enough to make it a data descriptor.
76
77
78Invoking Descriptors
79--------------------
80
81A descriptor can be called directly by its method name. For example,
82``d.__get__(obj)``.
83
84Alternatively, it is more common for a descriptor to be invoked automatically
85upon attribute access. For example, ``obj.d`` looks up ``d`` in the dictionary
86of ``obj``. If ``d`` defines the method :meth:`__get__`, then ``d.__get__(obj)``
87is invoked according to the precedence rules listed below.
88
89The details of invocation depend on whether ``obj`` is an object or a class.
Georg Brandl45cceeb2010-05-19 21:39:51 +000090
91For objects, the machinery is in :meth:`object.__getattribute__` which
92transforms ``b.x`` into ``type(b).__dict__['x'].__get__(b, type(b))``. The
93implementation works through a precedence chain that gives data descriptors
94priority over instance variables, instance variables priority over non-data
Benjamin Peterson57fb11b2014-10-06 21:10:25 -040095descriptors, and assigns lowest priority to :meth:`__getattr__` if provided.
96The full C implementation can be found in :c:func:`PyObject_GenericGetAttr()` in
97:source:`Objects/object.c`.
Georg Brandl45cceeb2010-05-19 21:39:51 +000098
99For classes, the machinery is in :meth:`type.__getattribute__` which transforms
100``B.x`` into ``B.__dict__['x'].__get__(None, B)``. In pure Python, it looks
101like::
102
103 def __getattribute__(self, key):
104 "Emulate type_getattro() in Objects/typeobject.c"
105 v = object.__getattribute__(self, key)
106 if hasattr(v, '__get__'):
107 return v.__get__(None, self)
108 return v
109
110The important points to remember are:
111
112* descriptors are invoked by the :meth:`__getattribute__` method
113* overriding :meth:`__getattribute__` prevents automatic descriptor calls
Georg Brandl45cceeb2010-05-19 21:39:51 +0000114* :meth:`object.__getattribute__` and :meth:`type.__getattribute__` make
115 different calls to :meth:`__get__`.
116* data descriptors always override instance dictionaries.
117* non-data descriptors may be overridden by instance dictionaries.
118
119The object returned by ``super()`` also has a custom :meth:`__getattribute__`
120method for invoking descriptors. The call ``super(B, obj).m()`` searches
121``obj.__class__.__mro__`` for the base class ``A`` immediately following ``B``
Benjamin Peterson910a6652013-10-18 12:57:55 -0400122and then returns ``A.__dict__['m'].__get__(obj, B)``. If not a descriptor,
Georg Brandl45cceeb2010-05-19 21:39:51 +0000123``m`` is returned unchanged. If not in the dictionary, ``m`` reverts to a
124search using :meth:`object.__getattribute__`.
125
Florent Xiclunaaa6c1d22011-12-12 18:54:29 +0100126The implementation details are in :c:func:`super_getattro()` in
Benjamin Peterson57fb11b2014-10-06 21:10:25 -0400127:source:`Objects/typeobject.c`. and a pure Python equivalent can be found in
128`Guido's Tutorial`_.
Georg Brandl45cceeb2010-05-19 21:39:51 +0000129
130.. _`Guido's Tutorial`: http://www.python.org/2.2.3/descrintro.html#cooperation
131
132The details above show that the mechanism for descriptors is embedded in the
133:meth:`__getattribute__()` methods for :class:`object`, :class:`type`, and
134:func:`super`. Classes inherit this machinery when they derive from
135:class:`object` or if they have a meta-class providing similar functionality.
136Likewise, classes can turn-off descriptor invocation by overriding
137:meth:`__getattribute__()`.
138
139
140Descriptor Example
141------------------
142
143The following code creates a class whose objects are data descriptors which
144print a message for each get or set. Overriding :meth:`__getattribute__` is
145alternate approach that could do this for every attribute. However, this
146descriptor is useful for monitoring just a few chosen attributes::
147
148 class RevealAccess(object):
149 """A data descriptor that sets and returns values
150 normally and prints a message logging their access.
151 """
152
153 def __init__(self, initval=None, name='var'):
154 self.val = initval
155 self.name = name
156
157 def __get__(self, obj, objtype):
158 print('Retrieving', self.name)
159 return self.val
160
161 def __set__(self, obj, val):
162 print('Updating', self.name)
163 self.val = val
164
165 >>> class MyClass(object):
166 x = RevealAccess(10, 'var "x"')
167 y = 5
168
169 >>> m = MyClass()
170 >>> m.x
171 Retrieving var "x"
172 10
173 >>> m.x = 20
174 Updating var "x"
175 >>> m.x
176 Retrieving var "x"
177 20
178 >>> m.y
179 5
180
181The protocol is simple and offers exciting possibilities. Several use cases are
182so common that they have been packaged into individual function calls.
183Properties, bound and unbound methods, static methods, and class methods are all
184based on the descriptor protocol.
185
186
187Properties
188----------
189
190Calling :func:`property` is a succinct way of building a data descriptor that
191triggers function calls upon access to an attribute. Its signature is::
192
193 property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
194
195The documentation shows a typical use to define a managed attribute ``x``::
196
197 class C(object):
198 def getx(self): return self.__x
199 def setx(self, value): self.__x = value
200 def delx(self): del self.__x
201 x = property(getx, setx, delx, "I'm the 'x' property.")
202
203To see how :func:`property` is implemented in terms of the descriptor protocol,
204here is a pure Python equivalent::
205
206 class Property(object):
207 "Emulate PyProperty_Type() in Objects/descrobject.c"
208
209 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
210 self.fget = fget
211 self.fset = fset
212 self.fdel = fdel
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700213 if doc is None and fget is not None:
214 doc = fget.__doc__
Georg Brandl45cceeb2010-05-19 21:39:51 +0000215 self.__doc__ = doc
216
217 def __get__(self, obj, objtype=None):
218 if obj is None:
219 return self
220 if self.fget is None:
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700221 raise AttributeError("unreadable attribute")
Georg Brandl45cceeb2010-05-19 21:39:51 +0000222 return self.fget(obj)
223
224 def __set__(self, obj, value):
225 if self.fset is None:
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700226 raise AttributeError("can't set attribute")
Georg Brandl45cceeb2010-05-19 21:39:51 +0000227 self.fset(obj, value)
228
229 def __delete__(self, obj):
230 if self.fdel is None:
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700231 raise AttributeError("can't delete attribute")
Georg Brandl45cceeb2010-05-19 21:39:51 +0000232 self.fdel(obj)
233
Raymond Hettinger632c8c82013-03-10 09:41:18 -0700234 def getter(self, fget):
235 return type(self)(fget, self.fset, self.fdel, self.__doc__)
236
237 def setter(self, fset):
238 return type(self)(self.fget, fset, self.fdel, self.__doc__)
239
240 def deleter(self, fdel):
241 return type(self)(self.fget, self.fset, fdel, self.__doc__)
242
Georg Brandl45cceeb2010-05-19 21:39:51 +0000243The :func:`property` builtin helps whenever a user interface has granted
244attribute access and then subsequent changes require the intervention of a
245method.
246
247For instance, a spreadsheet class may grant access to a cell value through
248``Cell('b10').value``. Subsequent improvements to the program require the cell
249to be recalculated on every access; however, the programmer does not want to
250affect existing client code accessing the attribute directly. The solution is
251to wrap access to the value attribute in a property data descriptor::
252
253 class Cell(object):
254 . . .
255 def getvalue(self, obj):
256 "Recalculate cell before returning value"
257 self.recalc()
258 return obj._value
259 value = property(getvalue)
260
261
262Functions and Methods
263---------------------
264
265Python's object oriented features are built upon a function based environment.
266Using non-data descriptors, the two are merged seamlessly.
267
268Class dictionaries store methods as functions. In a class definition, methods
269are written using :keyword:`def` and :keyword:`lambda`, the usual tools for
270creating functions. The only difference from regular functions is that the
271first argument is reserved for the object instance. By Python convention, the
272instance reference is called *self* but may be called *this* or any other
273variable name.
274
275To support method calls, functions include the :meth:`__get__` method for
276binding methods during attribute access. This means that all functions are
277non-data descriptors which return bound or unbound methods depending whether
278they are invoked from an object or a class. In pure python, it works like
279this::
280
281 class Function(object):
282 . . .
283 def __get__(self, obj, objtype=None):
284 "Simulate func_descr_get() in Objects/funcobject.c"
285 return types.MethodType(self, obj, objtype)
286
287Running the interpreter shows how the function descriptor works in practice::
288
289 >>> class D(object):
290 def f(self, x):
291 return x
292
293 >>> d = D()
294 >>> D.__dict__['f'] # Stored internally as a function
295 <function f at 0x00C45070>
296 >>> D.f # Get from a class becomes an unbound method
297 <unbound method D.f>
298 >>> d.f # Get from an instance becomes a bound method
299 <bound method D.f of <__main__.D object at 0x00B18C90>>
300
301The output suggests that bound and unbound methods are two different types.
Georg Brandl6faee4e2010-09-21 14:48:28 +0000302While they could have been implemented that way, the actual C implementation of
Benjamin Peterson57fb11b2014-10-06 21:10:25 -0400303:c:type:`PyMethod_Type` in :source:`Objects/classobject.c` is a single object
304with two different representations depending on whether the :attr:`im_self`
305field is set or is *NULL* (the C equivalent of *None*).
Georg Brandl45cceeb2010-05-19 21:39:51 +0000306
307Likewise, the effects of calling a method object depend on the :attr:`im_self`
308field. If set (meaning bound), the original function (stored in the
309:attr:`im_func` field) is called as expected with the first argument set to the
310instance. If unbound, all of the arguments are passed unchanged to the original
311function. The actual C implementation of :func:`instancemethod_call()` is only
312slightly more complex in that it includes some type checking.
313
314
315Static Methods and Class Methods
316--------------------------------
317
318Non-data descriptors provide a simple mechanism for variations on the usual
319patterns of binding functions into methods.
320
321To recap, functions have a :meth:`__get__` method so that they can be converted
322to a method when accessed as attributes. The non-data descriptor transforms a
323``obj.f(*args)`` call into ``f(obj, *args)``. Calling ``klass.f(*args)``
324becomes ``f(*args)``.
325
326This chart summarizes the binding and its two most useful variants:
327
328 +-----------------+----------------------+------------------+
329 | Transformation | Called from an | Called from a |
330 | | Object | Class |
331 +=================+======================+==================+
332 | function | f(obj, \*args) | f(\*args) |
333 +-----------------+----------------------+------------------+
334 | staticmethod | f(\*args) | f(\*args) |
335 +-----------------+----------------------+------------------+
336 | classmethod | f(type(obj), \*args) | f(klass, \*args) |
337 +-----------------+----------------------+------------------+
338
339Static methods return the underlying function without changes. Calling either
340``c.f`` or ``C.f`` is the equivalent of a direct lookup into
341``object.__getattribute__(c, "f")`` or ``object.__getattribute__(C, "f")``. As a
342result, the function becomes identically accessible from either an object or a
343class.
344
345Good candidates for static methods are methods that do not reference the
346``self`` variable.
347
348For instance, a statistics package may include a container class for
349experimental data. The class provides normal methods for computing the average,
350mean, median, and other descriptive statistics that depend on the data. However,
351there may be useful functions which are conceptually related but do not depend
352on the data. For instance, ``erf(x)`` is handy conversion routine that comes up
353in statistical work but does not directly depend on a particular dataset.
354It can be called either from an object or the class: ``s.erf(1.5) --> .9332`` or
355``Sample.erf(1.5) --> .9332``.
356
357Since staticmethods return the underlying function with no changes, the example
358calls are unexciting::
359
360 >>> class E(object):
361 def f(x):
362 print(x)
363 f = staticmethod(f)
364
365 >>> print(E.f(3))
366 3
367 >>> print(E().f(3))
368 3
369
370Using the non-data descriptor protocol, a pure Python version of
371:func:`staticmethod` would look like this::
372
373 class StaticMethod(object):
374 "Emulate PyStaticMethod_Type() in Objects/funcobject.c"
375
376 def __init__(self, f):
377 self.f = f
378
379 def __get__(self, obj, objtype=None):
380 return self.f
381
382Unlike static methods, class methods prepend the class reference to the
383argument list before calling the function. This format is the same
384for whether the caller is an object or a class::
385
386 >>> class E(object):
387 def f(klass, x):
388 return klass.__name__, x
389 f = classmethod(f)
390
391 >>> print(E.f(3))
392 ('E', 3)
393 >>> print(E().f(3))
394 ('E', 3)
395
396
397This behavior is useful whenever the function only needs to have a class
398reference and does not care about any underlying data. One use for classmethods
399is to create alternate class constructors. In Python 2.3, the classmethod
400:func:`dict.fromkeys` creates a new dictionary from a list of keys. The pure
401Python equivalent is::
402
Raymond Hettinger686aae42013-03-10 09:50:37 -0700403 class Dict(object):
Georg Brandl45cceeb2010-05-19 21:39:51 +0000404 . . .
405 def fromkeys(klass, iterable, value=None):
406 "Emulate dict_fromkeys() in Objects/dictobject.c"
407 d = klass()
408 for key in iterable:
409 d[key] = value
410 return d
411 fromkeys = classmethod(fromkeys)
412
413Now a new dictionary of unique keys can be constructed like this::
414
415 >>> Dict.fromkeys('abracadabra')
416 {'a': None, 'r': None, 'b': None, 'c': None, 'd': None}
417
418Using the non-data descriptor protocol, a pure Python version of
419:func:`classmethod` would look like this::
420
421 class ClassMethod(object):
422 "Emulate PyClassMethod_Type() in Objects/funcobject.c"
423
424 def __init__(self, f):
425 self.f = f
426
427 def __get__(self, obj, klass=None):
428 if klass is None:
429 klass = type(obj)
430 def newfunc(*args):
431 return self.f(klass, *args)
432 return newfunc
433