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

Albert-Jan Roskam fomcl at yahoo.com
Sun Sep 2 21:06:38 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);
>===> aha. So if I do len(Example(1, 2)) the C function "builtin_len" will be called, whereas if I formulate it like Example(1, 2).__len__(), only the __len__ special method of my own bogus class will be called. Interesting. I was already checking if I could find __builtin__.__len__, but that's not possible, probably because they're all compiled. 
>Thanks for your help!
>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))
>Tutor maillist  -  Tutor at python.org
>To unsubscribe or change subscription options:

From: Peter Otten <__peter__ at web.de>
To: tutor at python.org 
Sent: Sunday, September 2, 2012 2:36 PM
Subject: Re: [Tutor] making len() and __len__ return a non-int
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20120902/623471c7/attachment.html>

More information about the Tutor mailing list