P i
P i

Reputation: 30684

Do PyObject_GetItem and PyObject_SetItem work on PyType_List and PyType_Dict types?

Documentation for PyObject_GetItem and PyObject_SetItem here states:

PyObject* PyObject_GetItem(PyObject *o, PyObject *key) Return value: New reference.

Return element of o corresponding to the object key or NULL on failure. 
This is the equivalent of the Python expression o[key].

int PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v)

Map the object key to the value v. Returns -1 on failure. 
This is the equivalent of the Python statement o[key] = v.

foo[key] syntax implies PyType_Dict

However, it doesn't state whether it also works on PyType_List, in which case key would be an index, i.e. a positive PyType_Long, or maybe a type converts into it, e.g. a PyType_Bytes containing "42".

Does this function work for both containers?

I would expect it to; such a design to be in keeping with Python's "it does everything you would expect it to do" philosophy.

Furthermore, the project I'm looking at has a comment forewarning:

    // PyObject_SetItem is too weird to be using from C++
    // so it is intentionally omitted.

Should I be worried about this? What could it possibly mean? And has it been fixed for Python3?

Upvotes: 1

Views: 964

Answers (2)

P i
P i

Reputation: 30684

The answer is that it supports both!

You can find from the source code:

[email protected] ~ /Users/pi/Downloads/Python-3.4.2:
~ grep -R "PyObject_GetItem" .

: 
./Objects/abstract.c:PyObject_GetItem(PyObject *o, PyObject *key)
:

And looking in abstract.c:

    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 (PyIndex_Check(key)) {
                Py_ssize_t key_value;
                key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
                if (key_value == -1 && PyErr_Occurred())
                    return NULL;
                return PySequence_GetItem(o, key_value);
            }
            else if (o->ob_type->tp_as_sequence->sq_item)
                return type_error("sequence index must "
                                  "be integer, not '%.200s'", key);
        }

        return type_error("'%.200s' object is not subscriptable", o);
    }

Upvotes: 1

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798754

Both functions work for all containers that support indexed accesses, be they dict, list, tuple, string, bytes, and so on.

I'm not sure why PyCXX has that comment; it may be due to the fact that Python's dynamic typing does not always mesh well with languages with static typing.

Upvotes: 1

Related Questions