boost::python , dispatching in python

Arnaldur Gylfason arnaldur at decode.is
Wed Jan 9 18:18:38 CET 2002



I've been looking at the python interpreter
(parsetok,pythonrun,tokenizer,ceval,compile,...).
It's a lot of code!
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;


          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)
BINARY_ADD calls PyNumber_Add.
PyNumber_Add is :

PyObject *
PyNumber_Add(PyObject *v, PyObject *w)
{
     PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));
     if (result == Py_NotImplemented) {
          PySequenceMethods *m = v->ob_type->tp_as_sequence;
          Py_DECREF(Py_NotImplemented);
          if (m && m->sq_concat) {
               result = (*m->sq_concat)(v, w);
          }
                else {
                    PyErr_Format(
                   PyExc_TypeError,
                   "unsupported operand types for +: '%s' and '%s'",
                   v->ob_type->tp_name,
                   w->ob_type->tp_name);
                    result = NULL;
                }
     }
     return result;
}

It tries nb_add but sequence concat if it fails.


> > 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.








More information about the Cplusplus-sig mailing list