]> granicus.if.org Git - python/commitdiff
* Document how descriptors are invoked.
authorRaymond Hettinger <python@rcn.com>
Wed, 25 Jun 2003 18:29:36 +0000 (18:29 +0000)
committerRaymond Hettinger <python@rcn.com>
Wed, 25 Jun 2003 18:29:36 +0000 (18:29 +0000)
* Fix minor parenthesis matching errors in ref3.tex.

Doc/ref/ref3.tex

index a5a5d9f02f86963eec9d113c609b2d3d906171e9..50d8fa1a54bbd2c2178552585c7e8c414a5c8632 100644 (file)
@@ -481,8 +481,8 @@ function).
 
 Special read-only attributes: \member{im_self} is the class instance
 object, \member{im_func} is the function object;
-\member{im_class} is the class of \member{im_self} for bound methods,
-or the class that asked for the method for unbound methods);
+\member{im_class} is the class of \member{im_self} for bound methods
+or the class that asked for the method for unbound methods;
 \member{__doc__} is the method's documentation (same as
 \code{im_func.__doc__}); \member{__name__} is the method name (same as
 \code{im_func.__name__}); \member{__module__} is the name of the
@@ -907,7 +907,7 @@ except clause or with a finally clause.
 Slice objects are used to represent slices when \emph{extended slice
 syntax} is used.  This is a slice using two colons, or multiple slices
 or ellipses separated by commas, e.g., \code{a[i:j:step]}, \code{a[i:j,
-k:l]}, or \code{a[..., i:j])}.  They are also created by the built-in
+k:l]}, or \code{a[..., i:j]}.  They are also created by the built-in
 \function{slice()}\bifuncindex{slice} function.
 
 Special read-only attributes: \member{start} is the lower bound;
@@ -1249,6 +1249,66 @@ owner class.
 \end{methoddesc}
 
 
+\subsubsection{Invoking Descriptors \label{descriptor_invocation}}
+
+In general, a descriptor is an object attribute with ``binding behavior'',
+one whose attribute access has been overridden by methods in the descriptor
+protocol:  \method{__get__}, \method{__set__}, and \method{__delete__}.
+If any of those methods are defined for an object, it is said to be a
+descriptor.
+
+The default behavior for attribute access is to get, set, or delete the
+attribute from an object's dictionary. For instance, \code{a.x} has a
+lookup chain starting with \code{a.__dict__['x']}, then
+\code{type(a).__dict__['x']}, and continuing 
+through the base classes of \code{type(a)} excluding metaclasses.
+
+However, 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 and how they were called.  Note that
+descriptors are only invoked for new style objects or classes
+(ones that subclass \class{object} or \class{type}).
+
+The starting point for descriptor invocation is a binding, \code{a.x}.
+How the arguments are assembled depends on \code{a}:
+
+\begin{itemize}
+                      
+  \item[Direct Call] The simplest and least common call is when user code
+    directly invokes a descriptor method:    \code{x.__get__(a)}.
+
+  \item[Instance Binding]  If binding to a new-style object instance,
+    \code{a.x} is transformed into the call:
+    \code{type(a).__dict__['x'].__get__(a, type(a))}.
+                     
+  \item[Class Binding]  If binding to a new-style class, \code{A.x}
+    is transformed into the call: \code{A.__dict__['x'].__get__(None, A)}.
+
+  \item[Super Binding] If \code{a} is an instance of \class{super},
+    then the binding \code{super(B, obj).m()} searches
+    \code{obj.__class__.__mro__} for the base class \code{A} immediately
+    preceding \code{B} and then invokes the descriptor with the call:
+    \code{A.__dict__['m'].__get__(obj, A)}.
+                     
+\end{itemize}
+
+For instance bindings, the precedence of descriptor invocation depends
+on the which descriptor methods are defined.  Data descriptors define
+both \method{__get__} and \method{__set__}.  Non-data descriptors have
+just the \method{__get__} method.  Data descriptors always override
+a redefinition in an instance dictionary.  In contrast, non-data
+descriptors can be overridden by instances.
+
+Python methods (including \function{staticmethod} and \function{classmethod})
+are implemented as non-data descriptors.  Accordingly, instances can
+redefine and override methods.  This allows individual instances to acquire
+behaviors that differ from other instances of the same class.                     
+
+The \function{property} function is implemented as a data descriptor.
+Accordingly, instances cannot override the behavior a property.
+
+
 \subsection{Emulating callable objects\label{callable-types}}
 
 \begin{methoddesc}[object]{__call__}{self\optional{, args...}}