mirror of https://github.com/python/cpython
Finish off the type/class section; I don't think there's much else
to be covered in an overview article like this.
This commit is contained in:
parent
41cf5e0069
commit
b83769cb82
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
\documentclass{howto}
|
\documentclass{howto}
|
||||||
|
|
||||||
% $Id$
|
% $Id$
|
||||||
|
@ -14,7 +13,7 @@
|
||||||
|
|
||||||
{\large This document is a draft, and is subject to change until the
|
{\large This document is a draft, and is subject to change until the
|
||||||
final version of Python 2.2 is released. Currently it's up to date
|
final version of Python 2.2 is released. Currently it's up to date
|
||||||
for Python 2.2 alpha 4. Please send any comments, bug reports, or
|
for Python 2.2 beta 1. Please send any comments, bug reports, or
|
||||||
questions, no matter how minor, to \email{akuchlin@mems-exchange.org}.
|
questions, no matter how minor, to \email{akuchlin@mems-exchange.org}.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +146,8 @@ class C(object):
|
||||||
This means that \keyword{class} statements that don't have any base
|
This means that \keyword{class} statements that don't have any base
|
||||||
classes are always classic classes in Python 2.2. There's actually a
|
classes are always classic classes in Python 2.2. There's actually a
|
||||||
way to make new-style classes without any base classes, by setting the
|
way to make new-style classes without any base classes, by setting the
|
||||||
\member{__metaclass__} variable to XXX. (What do you set it to?)
|
\member{__metaclass__} variable to XXX (What do you set it to?), but
|
||||||
|
it's easier to just subclass \keyword{object}.
|
||||||
|
|
||||||
The type objects for the built-in types are available as built-ins,
|
The type objects for the built-in types are available as built-ins,
|
||||||
named using a clever trick. Python has always had built-in functions
|
named using a clever trick. Python has always had built-in functions
|
||||||
|
@ -163,62 +163,23 @@ factories when called.
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
To make the set of types complete, new type objects such as
|
To make the set of types complete, new type objects such as
|
||||||
\function{dictionary} and \function{file} have been added.
|
\function{dictionary} and \function{file} have been added. Here's a
|
||||||
|
more interesting example, adding a \method{lock()} method to file
|
||||||
Here's a more interesting example. The following class subclasses
|
objects:
|
||||||
Python's dictionary implementation in order to automatically fold all
|
|
||||||
dictionary keys to lowercase.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
class LowerCaseDict(dictionary):
|
class LockableFile(file):
|
||||||
def _fold_key (self, key):
|
def lock (self, operation, length=0, start=0, whence=0):
|
||||||
if not isinstance(key, str):
|
import fcntl
|
||||||
raise TypeError, "All keys must be strings"
|
return fcntl.lockf(self.fileno(), operation,
|
||||||
return key.lower()
|
length, start, whence)
|
||||||
|
|
||||||
def __getitem__ (self, key):
|
|
||||||
key = self._fold_key(key)
|
|
||||||
return dictionary.__getitem__(self, key)
|
|
||||||
|
|
||||||
def __setitem__ (self, key, value):
|
|
||||||
key = self._fold_key(key)
|
|
||||||
dictionary.__setitem__(self, key, value)
|
|
||||||
|
|
||||||
def __delitem__ (self, key):
|
|
||||||
key = self._fold_key(key)
|
|
||||||
dictionary.__delitem__(self, key, value)
|
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
Trying out this class, it works as you'd expect:
|
The now-obsolete \module{posixfile} module contained a class that
|
||||||
|
emulated all of a file object's methods and also added a
|
||||||
\begin{verbatim}
|
\method{lock()} method, but this class couldn't be passed to internal
|
||||||
>>> d = LowerCaseDict()
|
functions that expected a built-in file, something which is possible
|
||||||
>>> d['ABC'] = 1
|
with our new \class{LockableFile}.
|
||||||
>>> d['abc']
|
|
||||||
1
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
However, because it's a subclass of Python's dictionary type,
|
|
||||||
instances of \class{LowerCaseDict} can be used in most places where a
|
|
||||||
regular dictionary is required.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
>>> d = LowerCaseDict()
|
|
||||||
>>> exec 'Name = 1' in d
|
|
||||||
>>> print d.items()
|
|
||||||
XXX
|
|
||||||
>>> exec 'nAmE = name + 1' in d
|
|
||||||
>>> print d.items()
|
|
||||||
XXX
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
And now you can have Python with case-insensitive variable names! One
|
|
||||||
of the nice things about Python 2.2 is that it makes Python flexible
|
|
||||||
enough to solve many other past problems without hacking Python's C
|
|
||||||
code. If you want a case-insensitive Python environment, using a
|
|
||||||
case-folding dictionary and writing a case-insensitive tokenizer using
|
|
||||||
the compiler package (now automatically installed in 2.2) will make it
|
|
||||||
a straightforward.
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Descriptors}
|
\subsection{Descriptors}
|
||||||
|
@ -371,14 +332,100 @@ class{A}] after dropping duplicates.
|
||||||
|
|
||||||
Following this rule, referring to \method{D.save()} will return
|
Following this rule, referring to \method{D.save()} will return
|
||||||
\method{C.save()}, which is the behaviour we're after. This lookup
|
\method{C.save()}, which is the behaviour we're after. This lookup
|
||||||
rule is the same as the one followed by XXX Common Lisp?.
|
rule is the same as the one followed by Common Lisp.
|
||||||
|
|
||||||
|
|
||||||
\subsection{Attribute Access}
|
\subsection{Attribute Access}
|
||||||
|
|
||||||
XXX __getattribute__, __getattr__
|
A fair number of sophisticated Python classes define hooks for
|
||||||
|
attribute access using \method{__getattr__}; most commonly this is
|
||||||
|
done for convenience, to make code more readable by automatically
|
||||||
|
mapping an attribute access such as \code{obj.parent} into a method
|
||||||
|
call such as \code{obj.get_parent()}. Python 2.2 adds some new ways
|
||||||
|
of controlling attribute access.
|
||||||
|
|
||||||
|
First, \method{__getattr__(\var{attr_name})} is still supported by
|
||||||
|
new-style classes, and nothing about it has changed. As before, it
|
||||||
|
will be called when an attempt is made to access \code{obj.foo} and no
|
||||||
|
attribute named \samp{foo} is found in the instance's dictionary.
|
||||||
|
|
||||||
|
New-style classes also support a new method,
|
||||||
|
\method{__getattribute__(\var{attr_name})}. The difference between
|
||||||
|
the two methods is that \method{__getattribute__} is \emph{always}
|
||||||
|
called whenever any attribute is accessed, while the old
|
||||||
|
\method{__getattr__} is only called if \samp{foo} isn't found in the
|
||||||
|
instance's dictionary.
|
||||||
|
|
||||||
|
However, Python 2.2's support for \dfn{properties} will often be a
|
||||||
|
simpler way to trap attribute references. Writing a
|
||||||
|
\method{__getattr__} method is complicated because to avoid recursion
|
||||||
|
you can't use regular attribute accesses inside them, and instead have
|
||||||
|
to mess around with the contents of \member{__dict__}.
|
||||||
|
\method{__getattr__} methods also end up being called by Python when
|
||||||
|
it checks for other methods such as \method{__repr__} or
|
||||||
|
\method{__coerce__}, and so have to be written with this in mind.
|
||||||
|
Finally, calling a function on every attribute access results in a
|
||||||
|
sizable performance loss.
|
||||||
|
|
||||||
|
\class{property} is a new built-in type that packages up three
|
||||||
|
functions that get, set, or delete an attribute, and a docstring. For
|
||||||
|
example, if you want to define a \member{size} attribute that's
|
||||||
|
computed, but also settable, you could write:
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
class C:
|
||||||
|
def get_size (self):
|
||||||
|
result = ... computation ...
|
||||||
|
return result
|
||||||
|
def set_size (self, size):
|
||||||
|
... compute something based on the size
|
||||||
|
and set internal state appropriately ...
|
||||||
|
|
||||||
|
# Define a property. The 'delete this attribute'
|
||||||
|
# method is defined as None, so the attribute
|
||||||
|
# can't be deleted.
|
||||||
|
size = property(get_size, set_size,
|
||||||
|
None,
|
||||||
|
"Storage size of this instance")
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
That is certainly clearer and easier to write than a pair of
|
||||||
|
\method{__getattr__}/\method{__setattr__} methods that check for the
|
||||||
|
\member{size} attribute and handle it specially, while retrieving all
|
||||||
|
other attributes from the instance's \member{__dict__}. Accesses to
|
||||||
|
\member{size} are also the only ones which have to perform the work of
|
||||||
|
calling a function, letting references to other attributes run at
|
||||||
|
their usual speed.
|
||||||
|
|
||||||
|
Finally, it's possible to constrain the list of attributes that can be
|
||||||
|
referenced on an object using the new \member{__slots__} attribute.
|
||||||
|
Python objects are usually very dynamic; at any time it's possible to
|
||||||
|
define a new attribute on an instance by just doing
|
||||||
|
\code{obj.new_attr=1}. This is flexible and convenient, but this
|
||||||
|
flexibility can also lead to bugs, as when you meant to write
|
||||||
|
\code{obj.template = 'a'} but make a typo and wrote
|
||||||
|
\code{obj.templtae} by accident.
|
||||||
|
|
||||||
|
A new-style class can define a class variable named \member{__slots__}
|
||||||
|
to constrain the list of legal attribute names. An example will make
|
||||||
|
this clear:
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
>>> class C(object):
|
||||||
|
... __slots__ = ['template', 'name']
|
||||||
|
...
|
||||||
|
>>> obj = C()
|
||||||
|
>>> print obj.template
|
||||||
|
None
|
||||||
|
>>> obj.template = 'Test' ; obj.name = 'abc'
|
||||||
|
>>> print obj.template
|
||||||
|
Test
|
||||||
|
>>> obj.templtae
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in ?
|
||||||
|
AttributeError: 'C' object has no attribute 'templtae'
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
XXX properties, slots
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Related Links}
|
\subsection{Related Links}
|
||||||
|
@ -389,23 +436,26 @@ giving enough of an explanation to start you programming, but many
|
||||||
details have been simplified or ignored. Where should you go to get a
|
details have been simplified or ignored. Where should you go to get a
|
||||||
more complete picture?
|
more complete picture?
|
||||||
|
|
||||||
\url{http://www.python.org/2.2/descrintro.html} is a tutorial
|
\url{http://www.python.org/2.2/descrintro.html} is a lengthy tutorial
|
||||||
introduction to the descriptor features, written by Guido van Rossum.
|
introduction to the descriptor features, written by Guido van Rossum.
|
||||||
% XXX read it and comment on it
|
If my description has whetted your appetite, go read this tutorial
|
||||||
|
next, because it goes into much more detail about the new features
|
||||||
|
while still remaining quite easy to read.
|
||||||
|
|
||||||
Next, there are two relevant PEPs, \pep{252} and \pep{253}. \pep{252}
|
Next, there are two relevant PEPs, \pep{252} and \pep{253}. \pep{252}
|
||||||
is titled "Making Types Look More Like Classes", and covers the
|
is titled "Making Types Look More Like Classes", and covers the
|
||||||
descriptor API. \pep{253} is titled "Subtyping Built-in Types", and
|
descriptor API. \pep{253} is titled "Subtyping Built-in Types", and
|
||||||
describes the changes to type objects that make it possible to subtype
|
describes the changes to type objects that make it possible to subtype
|
||||||
built-in objects. This is the more complicated PEP of the two, and at
|
built-in objects. \pep{253} is the more complicated PEP of the two,
|
||||||
a few points the necessary explanations of types and meta-types may
|
and at a few points the necessary explanations of types and meta-types
|
||||||
cause your head to explode. Both PEPs were written and implemented by
|
may cause your head to explode. Both PEPs were written and
|
||||||
Guido van Rossum, with substantial assistance from the rest of the
|
implemented by Guido van Rossum, with substantial assistance from the
|
||||||
Zope Corp. team.
|
rest of the Zope Corp. team.
|
||||||
|
|
||||||
Finally, there's the ultimate authority: the source code.
|
Finally, there's the ultimate authority: the source code. Most of the
|
||||||
typeobject.c, others?
|
machinery for the type handling is in \file{Objects/typeobject.c}, but
|
||||||
% XXX point people at the right files
|
you should only resort to it after all other avenues have been
|
||||||
|
exhausted (including posting a question to python-list or python-dev.)
|
||||||
|
|
||||||
|
|
||||||
%======================================================================
|
%======================================================================
|
||||||
|
@ -1096,6 +1146,8 @@ embedding the interpreter, or just hacking on the interpreter itself.
|
||||||
If you only write Python code, none of the changes described here will
|
If you only write Python code, none of the changes described here will
|
||||||
affect you very much.
|
affect you very much.
|
||||||
|
|
||||||
|
% XXX PyArg_UnpackTuple()
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
|
|
||||||
\item Profiling and tracing functions can now be implemented in C,
|
\item Profiling and tracing functions can now be implemented in C,
|
||||||
|
@ -1295,10 +1347,10 @@ to experiment with these modules can uncomment them manually.
|
||||||
\section{Acknowledgements}
|
\section{Acknowledgements}
|
||||||
|
|
||||||
The author would like to thank the following people for offering
|
The author would like to thank the following people for offering
|
||||||
suggestions and corrections to various drafts of this article: Fred
|
suggestions, corrections and assistance with various drafts of this
|
||||||
Bremmer, Keith Briggs, Andrew Dalke, Fred~L. Drake, Jr., Carel
|
article: Fred Bremmer, Keith Briggs, Andrew Dalke, Fred~L. Drake, Jr.,
|
||||||
Fellinger, Mark Hammond, Stephen Hansen, Jack Jansen, Marc-Andr\'e
|
Carel Fellinger, Mark Hammond, Stephen Hansen, Jack Jansen,
|
||||||
Lemburg, Fredrik Lundh, Tim Peters, Neil Schemenauer, Guido van
|
Marc-Andr\'e Lemburg, Fredrik Lundh, Tim Peters, Tom Reinhardt, Neil
|
||||||
Rossum.
|
Schemenauer, Guido van Rossum.
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|
Loading…
Reference in New Issue