boost::python , dispatching in python
David Abrahams
david.abrahams at rcn.com
Wed Jan 9 19:10:29 CET 2002
----- Original Message -----
From: "Arnaldur Gylfason" <arnaldur at decode.is>
> I've been looking at the python interpreter
> (parsetok,pythonrun,tokenizer,ceval,compile,...).
> It's a lot of code!
With few comments!
> In ceval the operation is selected on the opcode that the tokenizer or
> something similar sets.
> I didn't see the place where the opcode is selected on the symbol.
> However the following in ceval handle, a + b and a[i]:
>
> case BINARY_ADD:
> w = POP();
> v = POP();
> if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
> /* INLINE: int + int */
> register long a, b, i;
> a = PyInt_AS_LONG(v);
> b = PyInt_AS_LONG(w);
> i = a + b;
> if ((i^a) < 0 && (i^b) < 0)
> goto slow_add;
> x = PyInt_FromLong(i);
> }
> else {
> slow_add:
> x = PyNumber_Add(v, w);
> }
> Py_DECREF(v);
> Py_DECREF(w);
> PUSH(x);
> if (x != NULL) continue;
> break;
So it looks like PyNumber_Add is the way to go for a + b
> case BINARY_SUBSCR:
> w = POP();
> v = POP();
> if (PyList_CheckExact(v) && PyInt_CheckExact(w)) {
> /* INLINE: list[int] */
> long i = PyInt_AsLong(w);
> if (i < 0)
> i += PyList_GET_SIZE(v);
> if (i < 0 ||
> i >= PyList_GET_SIZE(v)) {
> PyErr_SetString(PyExc_IndexError,
> "list index out of range");
> x = NULL;
> }
> else {
> x = PyList_GET_ITEM(v, i);
> Py_INCREF(x);
> }
> }
> else
> x = PyObject_GetItem(v, w);
> Py_DECREF(v);
> Py_DECREF(w);
> PUSH(x);
> if (x != NULL) continue;
> break;
>
> We can see that BINARY_SUBSCR tries list access first but key access
> otherwise (PyObject_GetItem).
> sequence access thus should probably have precedence over key access if
key
> is an integer (when an object has both sequence and mapping interfaces)
That's the wrong conclusion to draw. The check for list[int] is purely an
optimization, just like the check for int+int in the first case.
PyObject_GetItem() is the simple generalized routine that works for both
sequence and mapping protocols:
PyObject *
PyObject_GetItem(PyObject *o, PyObject *key)
{
PyMappingMethods *m;
if (o == NULL || key == NULL)
return null_error();
m = o->ob_type->tp_as_mapping;
if (m && m->mp_subscript)
return m->mp_subscript(o, key);
if (o->ob_type->tp_as_sequence) {
if (PyInt_Check(key))
return PySequence_GetItem(o, PyInt_AsLong(key));
else if (PyLong_Check(key)) {
long key_value = PyLong_AsLong(key);
if (key_value == -1 && PyErr_Occurred())
return NULL;
return PySequence_GetItem(o, key_value);
}
return type_error("sequence index must be integer");
}
return type_error("unsubscriptable object");
}
> BINARY_ADD calls PyNumber_Add.
<snip>
> PyNumber_Add is :
>
> It tries nb_add but sequence concat if it fails.
Okay.
> > > Yes. I'll take a look at the python source.
> > > In some cases we know how to handle things like o[i]: sequence access
> if i
> > > is integral, mapping access otherwise.
> >
> > Not neccessarily:
> >
> > x = { 1 : 'one', 2 : 'two' }
> > x[1]
>
> x is a dictionary so it only supports the mapping interface. No conflict
> with the sequence interface in this case.
There's no conflict, but the procedure you specified wouldn't work. Just use
PyObject_GetItem(). Almost every operation with a possible slot conflict has
a similar dispatcher, I'll wager.
-Dave
More information about the Cplusplus-sig
mailing list