Commit 192e490e authored by Ken Manheimer's avatar Ken Manheimer

Replace faulty references that had the (previously unnoticed!)

multiply rendered example sections.
parent 8d0ee8fc
......@@ -38,36 +38,6 @@
</PRE>
<p> The <a href="ExtensionClass.html">ExtensionClass</a>. release includes mix-in
extension base classes that can be used to add acquisition as a
feature to extension subclasses. These mix-in classes use the
context-wrapping feature of ExtensionClasses to implement
acquisition. Consider the following example::</p>
<p> import ExtensionClass, Acquisition</p>
<p> class C(ExtensionClass.Base):
color='red'</p>
<p> class A(Acquisition.Implicit):</p>
<p> def report(self):
print self.color</p>
<p> a=A()
c=C()
c.a=A()</p>
<p> c.a.report() # prints <code>red</code></p>
<p> d=C()
d.color='green'
d.a=a</p>
<p> d.a.report() # prints <code>green</code></p>
<p> a.report() # raises an attribute error</p>
<p> The class <code>A</code> inherits acquisition behavior from
<code>Acquisition.Implicit</code>. The object, <code>a</code>, "has" the color of
objects <code>c</code> and <code>d</code> when it is accessed through them, but it
......@@ -92,32 +62,18 @@
</PRE>
<p> Aquisition wrappers provide access to the wrapped objects
through the attributes <code>aq_parent</code>, <code>aq_self</code>, <code>aq_base</code>.
In the example above, the expressions::</p>
<p> <code>c.a.aq_parent is c</code></p>
<p> and:</p>
<PRE>
'c.a.aq_self is a'
</PRE>
<p> and::</p>
<p> <code>c.a.aq_self is a</code></p>
<p> both evaluate to true, but the expression:</p>
<PRE>
'c.a is a'
</PRE>
<p> both evaluate to true, but the expression::</p>
<p> <code>c.a is a</code></p>
<p> evaluates to false, because the expression <code>c.a</code> evaluates
to an acquisition wrapper around <code>c</code> and <code>a</code>, not <code>a</code> itself.</p>
......@@ -152,12 +108,6 @@
</PRE>
<p> When explicit acquisition is used, attributes are not
automatically obtained from the environment. Instead, the
method <code>aq_aquire</code> must be used, as in::</p>
<p> print c.a.aq_acquire(<code>color</code>)</p>
<p> To support explicit acquisition, an object should inherit
from the mix-in class <code>Acquisition.Explicit</code>.</p>
......@@ -183,14 +133,6 @@
</PRE>
<p> For example, in::</p>
<p> class C(Acquisition.Explicit):
id=1
secret=2
color=Acquisition.Acquired
__roles__=Acquisition.Acquired</p>
<p> The <em>only</em> attributes that are automatically acquired from
containing objects are <code>color</code>, and <code>__roles__</code>. Note also
that the <code>__roles__</code> attribute is acquired even though it's
......@@ -261,35 +203,6 @@
</PRE>
<p> For example, in::</p>
<p> from Acquisition import Explicit</p>
<p> class HandyForTesting:
def __init__(self, name): self.name=name
def __str__(self):
return "%s(%s)" % (self.name, self.__class__.__name__)
__repr__=__str__</p>
<p> class E(Explicit, HandyForTesting): pass</p>
<p> class Nice(HandyForTesting):
isNice=1
def __str__(self):
return HandyForTesting.__str__(self)+' and I am nice!'
__repr__=__str__</p>
<p> a=E(<code>a</code>)
a.b=E(<code>b</code>)
a.b.c=E(<code>c</code>)
a.p=Nice(<code>spam</code>)
a.b.p=E(<code>p</code>)</p>
<p> def find_nice(self, ancestor, name, object, extra):
return hasattr(object,'isNice') and object.isNice</p>
<p> print a.b.c.aq_acquire(<code>p</code>, find_nice)</p>
<p> The filtered acquisition in the last line skips over the first
attribute it finds with the name <code>p</code>, because the attribute
doesn't satisfy the condition given in the filter. The output of
......@@ -299,13 +212,6 @@
</PRE>
<p> The filtered acquisition in the last line skips over the first
attribute it finds with the name <code>p</code>, because the attribute
doesn't satisfy the condition given in the filter. The output of
the last line is::</p>
<p> spam(Nice) and I am nice!</p>
<h2>Acquisition and methods</h2>
......@@ -346,26 +252,6 @@
</PRE>
<p> Consider the following example::</p>
<p> from Acquisition import Implicit</p>
<p> class C(Implicit):
def __init__(self, name): self.name=name
def __str__(self):
return "%s(%s)" % (self.name, self.__class__.__name__)
__repr__=__str__</p>
<p> a=C("a")
a.b=C("b")
a.b.pref="spam"
a.b.c=C("c")
a.b.c.color="red"
a.b.c.pref="eggs"
a.x=C("x")</p>
<p> o=a.b.c.x</p>
<p> The expression <code>o.color</code> might be expected to return <code>"red"</code>. In
earlier versions of ExtensionClass, however, this expression
failed. Acquired acquiring objects did not acquire from the
......
......@@ -330,16 +330,6 @@
</PRE>
<p> Attribute lookup is performed by calling the base extension class
<code>getattr</code> operation for the base extension class that includes C
data, or for the first base extension class, if none of the base
extension classes include C data. <code>ExtensionClass.h</code> defines a
macro <code>Py_FindAttrString</code> that can be used to find an object's
attributes that are stored in the object's instance dictionary or
in the object's class or base classes::</p>
<p> v = Py_FindAttrString(self,name);</p>
<p> where <code>name</code> is a C string containing the attribute name.</p>
<p> In addition, a macro is provided that replaces <code>Py_FindMethod</code>
......@@ -405,22 +395,6 @@
</PRE>
<p> A problem occurs when trying to overide methods inherited from
Python base classes. Consider the following example::</p>
<p> from ExtensionClass import Base</p>
<p> class Spam:</p>
<p> def __init__(self, name):
self.name=name</p>
<p> class ECSpam(Base, Spam):</p>
<p> def __init__(self, name, favorite_color):
Spam.__init__(self,name)
self.favorite_color=favorite_color</p>
<p> This implementation will fail when an <code>ECSpam</code> object is
instantiated. The problem is that <code>ECSpam.__init__</code> calls
<code>Spam.__init__</code>, and <code>Spam.__init__</code> can only be called with a
......@@ -449,25 +423,6 @@
</PRE>
<p> To overcome this problem, extension classes provide a class method
<code>inheritedAttribute</code> that can be used to obtain an inherited
attribute that is suitable for calling with an extension class
instance. Using the <code>inheritedAttribute</code> method, the above
example can be rewritten as::</p>
<p> from ExtensionClass import Base</p>
<p> class Spam:</p>
<p> def __init__(self, name):
self.name=name</p>
<p> class ECSpam(Base, Spam):</p>
<p> def __init__(self, name, favorite_color):
ECSpam.inheritedAttribute(<code>__init__</code>)(self,name)
self.favorite_color=favorite_color</p>
<p> This isn't as pretty but does provide the desired result.</p>
......@@ -529,29 +484,6 @@
</PRE>
<p> Consider the following example::</p>
<p> import ExtensionClass</p>
<p> class CustomMethod(ExtensionClass.Base):</p>
<p> def __call__(self,ob):
print <code>a %s was called</code> % ob.__class__.__name__</p>
<p> class wrapper:</p>
<p> def __init__(self,m,o): self.meth, self.ob=m,o</p>
<p> def __call__(self): self.meth(self.ob)</p>
<p> def __of__(self,o): return self.wrapper(self,o)</p>
<p> class bar(ExtensionClass.Base):
hi=CustomMethod()</p>
<p> x=bar()
hi=x.hi()</p>
<p> Note that <code>ExtensionClass.Base</code> is a base extension class that
provides very basic ExtensionClass behavior. </p>
......@@ -651,23 +583,6 @@
</PRE>
<p> For example::</p>
<p> class C(ExtensionClass.Base):</p>
<p> def get_secret(self):
"Get a secret"
....</p>
<p> c=C()</p>
<p> c.f.__roles__=['Trusted People']</p>
<p> print c.f.__roles__ # outputs ['Trusted People']
print c.f__roles__ # outputs ['Trusted People']</p>
<p> print C.f.__roles__ # fails, unbound method</p>
<p> A bound method attribute is set by setting an attribute in it's
instance with a name consisting of the concatination of the
method's <code>__name__</code> attribute and the attribute name.
......
......@@ -169,166 +169,6 @@
</PRE>
<p> Consider an implementation of a MultiMapping extension type,
without use of the extension class mechanism::</p>
<p> #include "Python.h"</p>
<p> #define UNLESS(E) if(!(E))</p>
<p> typedef struct {
PyObject_HEAD
PyObject *data;
} MMobject;</p>
<p> staticforward PyTypeObject MMtype;</p>
<p> static PyObject *
MM_push(MMobject *self, PyObject *args){
PyObject *src;
UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}</p>
<p> static PyObject *
MM_pop(MMobject *self, PyObject *args){
long l;
PyObject *r;
static PyObject *emptyList=0;</p>
<p> UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL;
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
UNLESS(-1 != (l=PyList_Size(self->data))) return NULL;
l--;
UNLESS(r=PySequence_GetItem(self->data,l)) return NULL;
UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err;
return r;
err:
Py_DECREF(r);
return NULL;
}</p>
<p> static struct PyMethodDef MM_methods[] = {
{"push", (PyCFunction) MM_push, 1,
"push(mapping_object) -- Add a data source"},
{"pop", (PyCFunction) MM_pop, 1,
"pop() -- Remove and return the last data source added"},
{NULL, NULL} /* sentinel */
};</p>
<p> static PyObject *
newMMobject(PyObject *ignored, PyObject *args){
MMobject *self;</p>
<p> UNLESS(PyArg_ParseTuple(args, "")) return NULL;
UNLESS(self = PyObject_NEW(MMobject, &MMtype)) return NULL;
UNLESS(self->data=PyList_New(0)) goto err;
return (PyObject *)self;
err:
Py_DECREF(self);
return NULL;
}</p>
<p> static void
MM_dealloc(MMobject *self){
Py_XDECREF(self->data);
PyMem_DEL(self);
}</p>
<p> static PyObject *
MM_getattr(MMobject *self, char *name){
return Py_FindMethod(MM_methods, (PyObject *)self, name);
}</p>
<p> static int
MM_length(MMobject *self){
long l=0, el, i;
PyObject *e=0;</p>
<p> UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
while(--i >= 0)
{
e=PyList_GetItem(self->data,i);
UNLESS(-1 != (el=PyObject_Length(e))) return -1;
l+=el;
}
return l;
}</p>
<p> static PyObject *
MM_subscript(MMobject *self, PyObject *key){
long i;
PyObject *e;</p>
<p> UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while(--i >= 0)
{
e=PyList_GetItem(self->data,i);
if(e=PyObject_GetItem(e,key)) return e;
PyErr_Clear();
}
PyErr_SetObject(PyExc_KeyError,key);
return NULL;
}</p>
<p> static PyMappingMethods MM_as_mapping = {
(inquiry)MM_length, /*mp_length*/
(binaryfunc)MM_subscript, /*mp_subscript*/
(objobjargproc)NULL, /*mp_ass_subscript*/
};</p>
<p> /* -------------------------------------------------------- */</p>
<p> static char MMtype__doc__[] =
"MultiMapping -- Combine multiple mapping objects for lookup"
;</p>
<p> static PyTypeObject MMtype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"MultMapping", /*tp_name*/
sizeof(MMobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)MM_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)MM_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&MM_as_mapping, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/</p>
<p> /* Space for future expansion <em>/
0L,0L,0L,0L,
MMtype__doc__ /</em> Documentation string */
};</p>
<p> static struct PyMethodDef MultiMapping_methods[] = {
{"MultiMapping", (PyCFunction)newMMobject, 1,
"MultiMapping() -- Create a new empty multi-mapping"},
{NULL, NULL} /* sentinel */
};</p>
<p> void
initMultiMapping(){
PyObject *m;</p>
<p> m = Py_InitModule4(
"MultiMapping", MultiMapping_methods,
"MultiMapping -- Wrap multiple mapping objects for lookup",
(PyObject*)NULL,PYTHON_API_VERSION);</p>
<p> if (PyErr_Occurred())
Py_FatalError("can't initialize module MultiMapping");
}</p>
<p> This module defines an extension type, <code>MultiMapping</code>, and exports a
module function, <code>MultiMapping</code>, that creates <code>MultiMapping</code>
Instances. The type provides two methods, <code>push</code>, and <code>pop</code>, for
......@@ -521,188 +361,6 @@
</PRE>
<p> Now consider an extension class implementation of MultiMapping
objects::</p>
<p> #include "Python.h"
#include "ExtensionClass.h"</p>
<p> #define UNLESS(E) if(!(E))</p>
<p> typedef struct {
PyObject_HEAD
PyObject *data;
} MMobject;</p>
<p> staticforward PyExtensionClass MMtype;</p>
<p> static PyObject *
MM_push(self, args)
MMobject *self;
PyObject *args;
{
PyObject *src;
UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}</p>
<p> static PyObject *
MM_pop(self, args)
MMobject *self;
PyObject *args;
{
long l;
PyObject *r;
static PyObject *emptyList=0;</p>
<p> UNLESS(emptyList) UNLESS(emptyList=PyList_New(0)) return NULL;
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
UNLESS(-1 != (l=PyList_Size(self->data))) return NULL;
l--;
UNLESS(r=PySequence_GetItem(self->data,l)) return NULL;
UNLESS(-1 != PyList_SetSlice(self->data,l,l+1,emptyList)) goto err;
return r;
err:
Py_DECREF(r);
return NULL;
}</p>
<p> static PyObject *
MM__init__(self, args)
MMobject *self;
PyObject *args;
{
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
UNLESS(self->data=PyList_New(0)) goto err;
Py_INCREF(Py_None);
return Py_None;
err:
Py_DECREF(self);
return NULL;
}</p>
<p> static struct PyMethodDef MM_methods[] = {
{"__init__", (PyCFunction)MM__init__, 1,
"__init__() -- Create a new empty multi-mapping"},
{"push", (PyCFunction) MM_push, 1,
"push(mapping_object) -- Add a data source"},
{"pop", (PyCFunction) MM_pop, 1,
"pop() -- Remove and return the last data source added"},
{NULL, NULL} /* sentinel */
};</p>
<p> static void
MM_dealloc(self)
MMobject *self;
{
Py_XDECREF(self->data);
PyMem_DEL(self);
}</p>
<p> static PyObject *
MM_getattr(self, name)
MMobject *self;
char *name;
{
return Py_FindMethod(MM_methods, (PyObject *)self, name);
}</p>
<p> static int
MM_length(self)
MMobject *self;
{
long l=0, el, i;
PyObject *e=0;</p>
<p> UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
while(--i >= 0)
{
e=PyList_GetItem(self->data,i);
UNLESS(-1 != (el=PyObject_Length(e))) return -1;
l+=el;
}
return l;
}</p>
<p> static PyObject *
MM_subscript(self, key)
MMobject *self;
PyObject *key;
{
long i;
PyObject *e;</p>
<p> UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while(--i >= 0)
{
e=PyList_GetItem(self->data,i);
if(e=PyObject_GetItem(e,key)) return e;
PyErr_Clear();
}
PyErr_SetObject(PyExc_KeyError,key);
return NULL;
}</p>
<p> static PyMappingMethods MM_as_mapping = {
(inquiry)MM_length, /*mp_length*/
(binaryfunc)MM_subscript, /*mp_subscript*/
(objobjargproc)NULL, /*mp_ass_subscript*/
};</p>
<p> /* -------------------------------------------------------- */</p>
<p> static char MMtype__doc__[] =
"MultiMapping -- Combine multiple mapping objects for lookup"
;</p>
<p> static PyExtensionClass MMtype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"MultMapping", /*tp_name*/
sizeof(MMobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)MM_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)MM_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&MM_as_mapping, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/</p>
<p> /* Space for future expansion <em>/
0L,0L,0L,0L,
MMtype__doc__, /</em> Documentation string */
METHOD_CHAIN(MM_methods)
};</p>
<p> static struct PyMethodDef MultiMapping_methods[] = {
{NULL, NULL} /* sentinel */
};</p>
<p> void
initMultiMapping()
{
PyObject *m, *d;</p>
<p> m = Py_InitModule4(
"MultiMapping", MultiMapping_methods,
"MultiMapping -- Wrap multiple mapping objects for lookup",
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"MultiMapping",MMtype);</p>
<p> if (PyErr_Occurred())
Py_FatalError("can't initialize module MultiMapping");
}</p>
<p> This version includes <code>ExtensionClass.h</code>. The two declarations of
<code>MMtype</code> have been changed from <code>PyTypeObject</code> to <code>PyExtensionClass</code>.
The <code>METHOD_CHAIN</code> macro has been used to add methods to the end of
......@@ -715,16 +373,6 @@
</PRE>
<p> This version includes <code>ExtensionClass.h</code>. The two declarations of
<code>MMtype</code> have been changed from <code>PyTypeObject</code> to <code>PyExtensionClass</code>.
The <code>METHOD_CHAIN</code> macro has been used to add methods to the end of
the definition for <code>MMtype</code>. The module function, newMMobject has
been replaced by the <code>MMtype</code> method, <code>MM__init__</code>. Note that this
method does not create or return a new object. Finally, the lines::</p>
<p> d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"MultiMapping",MMtype);</p>
<p> Have been added to both initialize the extension class and to export
it in the module dictionary.</p>
......@@ -743,19 +391,6 @@
</PRE>
<p> To use this module, compile, link, and import it as with any other
extension module. The following python code illustrates the
module's use::</p>
<p> from MultiMapping import MultiMapping
m=MultiMapping()
m.push({'spam':1, <code>eggs</code>:2})
m.push({'spam':3, <code>ham</code>:4})</p>
<p> m['spam'] # returns 3
m['ham'] # returns 4
m['foo'] # raises a key error</p>
<p> Creating the <code>MultiMapping</code> object took three steps, one to create
an empty <code>MultiMapping</code>, and two to add mapping objects to it. We
might wish to simplify the process of creating MultiMapping
......@@ -777,25 +412,6 @@
</PRE>
<p> Creating the <code>MultiMapping</code> object took three steps, one to create
an empty <code>MultiMapping</code>, and two to add mapping objects to it. We
might wish to simplify the process of creating MultiMapping
objects by providing a constructor that takes source mapping
objects as parameters. We can do this by sub-classing MultiMapping
in Python::</p>
<p> from MultiMapping import MultiMapping
class ExtendedMultiMapping(MultiMapping):
def __init__(self,*data):
MultiMapping.__init__(self)
for d in data: self.push(d)</p>
<p> m=ExtendedMultiMapping({'spam':1, <code>eggs</code>:2}, {'spam':3, <code>ham</code>:4})</p>
<p> m['spam'] # returns 3
m['ham'] # returns 4
m['foo'] # raises a key error</p>
<p> Note that the source file included in the ExtensionClass
distribution has numerous enhancements beyond the version shown in
this document.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment