diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -4,6 +4,7 @@ :Author: Raymond Hettinger :Contact: +:Release: 2.0 .. Contents:: @@ -23,42 +24,61 @@ Definition and Introduction --------------------------- -In general, a descriptor is an object attribute with "binding behavior", one -whose attribute access has been overridden by methods in the descriptor -protocol. Those methods are :meth:`__get__`, :meth:`__set__`, and -:meth:`__delete__`. If any of those methods are defined for an object, it is -said to be a descriptor. +A :term:`descriptor` is an object that defines any of the methods of the +descriptor protocol (i.e. :meth:`__get__`, :meth:`__set__`, or +:meth:`__delete__`). The main function of descriptors is customizing the +behavior of attributes. -The default behavior for attribute access is to get, set, or delete the -attribute from an object's dictionary. For instance, ``a.x`` has a lookup chain -starting with ``a.__dict__['x']``, then ``type(a).__dict__['x']``, and -continuing through the base classes of ``type(a)`` excluding metaclasses. If the -looked-up value is an object defining one of the descriptor methods, then Python -may override the default behavior and invoke the descriptor method instead. -Where this occurs in the precedence chain depends on which descriptor methods -were defined. +If an object's attribute is defined as a descriptor, then looking up or setting +the value of the attribute will actually invoke special methods on the +descriptor instead. If this sounds like :func:`properties `, that's +because they are implemented as descriptors. -Descriptors are a powerful, general purpose protocol. They are the mechanism -behind properties, methods, static methods, class methods, and :func:`super()`. -They are used throughout Python itself to implement the new style classes -introduced in version 2.2. Descriptors simplify the underlying C-code and offer -a flexible set of new tools for everyday Python programs. +Typical behavior for attribute access is to get, set, or delete the attribute +from an object's dictionary. For instance, ``a.x`` has a lookup chain starting +with ``a.__dict__['x']``, then ``type(a).__dict__['x']``, and continuing +through the base classes of ``type(a)``. If the found value is an object +defining one of the descriptor methods, then Python will invoke a descriptor +method instead. Where this occurs in the precedence chain depends on which +descriptor methods are defined. + +Descriptors implements a powerful, general purpose protocol. They are also +the mechanism behind properties methods, static methods, class methods, and +:func:`super()`. They are used throughout Python itself to implement the +new style classes introduced in version 2.2. Descriptors simplify the +underlying C code and offer a flexible set of new tools for everyday Python +programs. Descriptor Protocol ------------------- -``descr.__get__(self, obj, type=None) --> value`` +The descriptor protocol defines three methods: :meth:`__get__`, +:meth:`__set__`, and :meth:`__delete__`: -``descr.__set__(self, obj, value) --> None`` +.. method:: descr.__get__(self, obj, type=None) -> value -``descr.__delete__(self, obj) --> None`` + The :meth:`__get__` method is invoked when getting an attribute's value. + The values passed to it depends on whether the attribute was looked up on + an object or on a class. If looked up on an object, :meth:`__get__` is + passed the object and the class of the object. If looked up on a class, + it is passed `None` and the class. The value it returns will be used as + the value of the attribute. -That is all there is to it. Define any of these methods and an object is -considered a descriptor and can override default behavior upon being looked up -as an attribute. +.. method:: descr.__set__(self, obj, value) -> None -If an object defines both :meth:`__get__` and :meth:`__set__`, it is considered + The :meth:`__set__` method is invoked when setting an attribute's value. + It is passed the object and the value to set. + +.. method:: descr.__delete__(self, obj) -> None + + The :meth:`__delete__` method is invoked to delete the attribute, and is + passed the object. + +That is all there is to it. Define any of these methods and an object is a +descriptor and can override default behavior when found as an attribute. + +If an object defines both :meth:`__get__` and :meth:`__set__`, it is called a data descriptor. Descriptors that only define :meth:`__get__` are called non-data descriptors (they are typically used for methods but other uses are possible). @@ -78,10 +98,7 @@ Invoking Descriptors -------------------- -A descriptor can be called directly by its method name. For example, -``d.__get__(obj)``. - -Alternatively, it is more common for a descriptor to be invoked automatically +Descriptors are invoked automatically upon attribute access. For example, ``obj.d`` looks up ``d`` in the dictionary of ``obj``. If ``d`` defines the method :meth:`__get__`, then ``d.__get__(obj)`` is invoked according to the precedence rules listed below. @@ -262,7 +279,7 @@ Functions and Methods --------------------- -Python's object oriented features are built upon a function based environment. +Python's object oriented features are built upon a function-based environment. Using non-data descriptors, the two are merged seamlessly. Class dictionaries store methods as functions. In a class definition, methods