diff options
-rw-r--r-- | Doc/tut.tex | 119 | ||||
-rw-r--r-- | Doc/tut/tut.tex | 119 |
2 files changed, 194 insertions, 44 deletions
diff --git a/Doc/tut.tex b/Doc/tut.tex index 32ebc0e..340be69 100644 --- a/Doc/tut.tex +++ b/Doc/tut.tex @@ -2438,28 +2438,8 @@ Methods may call other methods by using method attributes of the The instantiation operation (``calling'' a class object) creates an empty object. Many classes like to create objects in a known initial -state. In early versions of Python, there was no special syntax to -enforce this (see below), but a convention was widely used: -add a method named \verb\init\ to the class, -which initializes the instance (by assigning to some important data -attributes) and returns the instance itself. For example, class -\verb\Bag\ above could have the following method: - -\begin{verbatim} - def init(self): - self.empty() - return self -\end{verbatim} - -The client can then create and initialize an instance in one -statement, as follows: - -\begin{verbatim} - x = Bag().init() -\end{verbatim} - -In later versions of Python, a special method named \verb\__init__\ may be -defined instead: +state. Therefore a class may define a special method named +\verb\__init__\, like this: \begin{verbatim} def __init__(self): @@ -3052,4 +3032,99 @@ raise an exception. For example: f.close() \end{verbatim} + +\section{New Class Features in Release 1.1} + +Two changes have been made to classes: the operator overloading +mechanism is more flexible, providing more support for non-numeric use +of operators, and it is possible to trap attribute accesses. + +\subsection{New Operator Overloading} + +It is no longer necessary to coerce both sides of an operator to the +same class or type. A class may still provide a \code{__coerce__} +method, but this method may return objects of different types or +classes if it feels like it. If no \code{__coerce__} is defined, any +argument type or class is acceptable. + +In order to make it possible to implement binary operators where the +right-hand side is a class instance but the left-hand side is not, +without using coercions, right-hand versions of all binary operators +may be defined. These have an `r' prepended to their name, +e.g. \code{__radd__}. + +For example, here's a very simple class for representing times. Times +are initialized from a number of seconds (like time.time()). Times +are printed like this: \code{Thu Oct 6 14:20:06 1994}. Subtracting +two Times gives their difference in seconds. Adding or subtracting a +Time and a number gives a new Time. You can't add two times, nor can +you subtract a Time from a number. + +\begin{verbatim} +import time + +class Time: + def __init__(self, seconds): + self.seconds = seconds + def __repr__(self): + return time.ctime(self.seconds) + def __add__(self, x): + return Time(self.seconds + x) + __radd__ = __add__ # support for x+t + def __sub__(self, x): + if hasattr(x, 'seconds'): # test if x could be a Time + return self.seconds - x.seconds + else: + return self.seconds - x + +now = Time(time.time()) +tomorrow = 24*3600 + now +yesterday = now - today +print tomorrow - yesterday # prints 172800 +\end{verbatim} + +\subsection{Trapping Attribute Access} + +You can define three new ``magic'' methods in a class now: +\code{__getattr__(self, name)}, \code{__setattr__(self, name, value)} +and \code{__delattr__(self, name)}. + +The \code{__getattr__} method is called when an attribute access fails, +i.e. when an attribute access would otherwise raise AttributeError -- +this is {\em after} the instance's dictionary and its class hierarchy +have been searched for the named attribute. Note that if this method +attempts to access any undefined instance attribute it will be called +recursively! + +The \code{__setattr__} and \code{__delattr__} methods are called when +assignment to, respectively deletion of an attribute are attempted. +They are called {\em instead} of the normal action (which is to insert +or delete the attribute in the instance dictionary). If either of +these methods most set or delete any attribute, they can only do so by +using the instance dictionary directly -- \code{self.__dict__} -- else +they would be called recursively. + +For example, here's a near-universal ``Wrapper'' class that passes all +its attribute accesses to another object. Note how the +\code{__init__} method inserts the wrapped object in +\code{self.__dict__} in order to avoid endless recursion +(\code{__setattr__} would call \code{__getattr__} which would call +itself recursively). + +\begin{verbatim} +class Wrapper: + def __init__(self, wrapped): + self.__dict__['wrapped'] = wrapped + def __getattr__(self, name): + return getattr(self.wrapped, name) + def __setattr__(self, name, value): + setattr(self.wrapped, value) + def __delattr__(self, name): + delattr(self.wrapped, name) + +import sys +f = Wrapper(sys.stdout) +f.write('hello world\n') # prints 'hello world' +\end{verbatim} + \end{document} diff --git a/Doc/tut/tut.tex b/Doc/tut/tut.tex index 32ebc0e..340be69 100644 --- a/Doc/tut/tut.tex +++ b/Doc/tut/tut.tex @@ -2438,28 +2438,8 @@ Methods may call other methods by using method attributes of the The instantiation operation (``calling'' a class object) creates an empty object. Many classes like to create objects in a known initial -state. In early versions of Python, there was no special syntax to -enforce this (see below), but a convention was widely used: -add a method named \verb\init\ to the class, -which initializes the instance (by assigning to some important data -attributes) and returns the instance itself. For example, class -\verb\Bag\ above could have the following method: - -\begin{verbatim} - def init(self): - self.empty() - return self -\end{verbatim} - -The client can then create and initialize an instance in one -statement, as follows: - -\begin{verbatim} - x = Bag().init() -\end{verbatim} - -In later versions of Python, a special method named \verb\__init__\ may be -defined instead: +state. Therefore a class may define a special method named +\verb\__init__\, like this: \begin{verbatim} def __init__(self): @@ -3052,4 +3032,99 @@ raise an exception. For example: f.close() \end{verbatim} + +\section{New Class Features in Release 1.1} + +Two changes have been made to classes: the operator overloading +mechanism is more flexible, providing more support for non-numeric use +of operators, and it is possible to trap attribute accesses. + +\subsection{New Operator Overloading} + +It is no longer necessary to coerce both sides of an operator to the +same class or type. A class may still provide a \code{__coerce__} +method, but this method may return objects of different types or +classes if it feels like it. If no \code{__coerce__} is defined, any +argument type or class is acceptable. + +In order to make it possible to implement binary operators where the +right-hand side is a class instance but the left-hand side is not, +without using coercions, right-hand versions of all binary operators +may be defined. These have an `r' prepended to their name, +e.g. \code{__radd__}. + +For example, here's a very simple class for representing times. Times +are initialized from a number of seconds (like time.time()). Times +are printed like this: \code{Thu Oct 6 14:20:06 1994}. Subtracting +two Times gives their difference in seconds. Adding or subtracting a +Time and a number gives a new Time. You can't add two times, nor can +you subtract a Time from a number. + +\begin{verbatim} +import time + +class Time: + def __init__(self, seconds): + self.seconds = seconds + def __repr__(self): + return time.ctime(self.seconds) + def __add__(self, x): + return Time(self.seconds + x) + __radd__ = __add__ # support for x+t + def __sub__(self, x): + if hasattr(x, 'seconds'): # test if x could be a Time + return self.seconds - x.seconds + else: + return self.seconds - x + +now = Time(time.time()) +tomorrow = 24*3600 + now +yesterday = now - today +print tomorrow - yesterday # prints 172800 +\end{verbatim} + +\subsection{Trapping Attribute Access} + +You can define three new ``magic'' methods in a class now: +\code{__getattr__(self, name)}, \code{__setattr__(self, name, value)} +and \code{__delattr__(self, name)}. + +The \code{__getattr__} method is called when an attribute access fails, +i.e. when an attribute access would otherwise raise AttributeError -- +this is {\em after} the instance's dictionary and its class hierarchy +have been searched for the named attribute. Note that if this method +attempts to access any undefined instance attribute it will be called +recursively! + +The \code{__setattr__} and \code{__delattr__} methods are called when +assignment to, respectively deletion of an attribute are attempted. +They are called {\em instead} of the normal action (which is to insert +or delete the attribute in the instance dictionary). If either of +these methods most set or delete any attribute, they can only do so by +using the instance dictionary directly -- \code{self.__dict__} -- else +they would be called recursively. + +For example, here's a near-universal ``Wrapper'' class that passes all +its attribute accesses to another object. Note how the +\code{__init__} method inserts the wrapped object in +\code{self.__dict__} in order to avoid endless recursion +(\code{__setattr__} would call \code{__getattr__} which would call +itself recursively). + +\begin{verbatim} +class Wrapper: + def __init__(self, wrapped): + self.__dict__['wrapped'] = wrapped + def __getattr__(self, name): + return getattr(self.wrapped, name) + def __setattr__(self, name, value): + setattr(self.wrapped, value) + def __delattr__(self, name): + delattr(self.wrapped, name) + +import sys +f = Wrapper(sys.stdout) +f.write('hello world\n') # prints 'hello world' +\end{verbatim} + \end{document} |