[Tutor] making len() and __len__ return a non-int

Peter Otten __peter__ at web.de
Sun Sep 2 14:36:49 CEST 2012


Albert-Jan Roskam wrote:

> If I implement __len__ in my own class, does it really have to return an
> int? Is there no way around this (other than modifying the source code of
> python itself ;-) It would be nice if len(Example(row, col)) would return
> a dictionary, or a two-tuple (see code below). The strange thing is that
> calling __len__ directly does work: Example(1, 2).__len__() returns the
> dictionary. I always thought len() was a convenient "shorthand" for
> __len__. I've even been reading about metaclasses (interesting, dark,
> mysterious), thinking the answer might lie there. Note that my question is
> not whether it's a good idea to do this, 

Ah, you already know it's a bad idea...

> I just find it interesting to understand how it could be done.

It cannot be done without modifying the source.

Here's the implementation of len() in Python 3.3:

static PyObject *
builtin_len(PyObject *self, PyObject *v)
{
    Py_ssize_t res;

    res = PyObject_Size(v);
    if (res < 0 && PyErr_Occurred())
        return NULL;
    return PyLong_FromSsize_t(res);
}

I did not successfully drill down further, but you can see that it may 
signal an error or return a Python long (which I think is the same as a 
Python int in 3.x) and that the underlying code operates on Py_size_t, so 
you'd have to modify that code, too. Py_ssize_t is implementation dependent 
-- on my 64-bit Linux valid lengths are in range(0, 2**63):

>>> class A:
...     def __len__(self): return self._len
...     def __init__(self, len):
...             self._len = len
... 
>>> len(A(-1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: __len__() should return >= 0
>>> len(A(2**63))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: cannot fit 'int' into an index-sized integer
>>> len(A(2**63-1))
9223372036854775807




More information about the Tutor mailing list