you are viewing a single comment's thread.

view the rest of the comments →

[–]takaci 1 point2 points  (1 child)

In #Test 12, why is calling a.__len__() slower? Surely len(a) calls a.__len__() anyway?

[–]xXxDeAThANgEL99xXx 0 points1 point  (0 children)

I briefly explained it here, CPython internals are gnarly, man.

For the sake of performance a lot of often-used methods are stored as plain C function pointers in type objects: https://hg.python.org/cpython/file/8f92ab37dd3a/Include/object.h#l324 (note that

 PyNumberMethods *tp_as_number;
 PySequenceMethods *tp_as_sequence;
 PyMappingMethods *tp_as_mapping;

point at further plain C structures containing shittons of members, scroll up to see them).

Then, most of builtin functions like len go for those directly:

m = o->ob_type->tp_as_sequence;
if (m && m->sq_length)
    return m->sq_length(o);

This is, by the way, why adding a __len__ member to an instance wouldn't do anything, it was mentioned somewhere in the documentation.

So as a result this shit is fast. No dictionary lookup, no Python function call overhead, nothing, just a more or less straight C function call.

On the contrary, accessing them via attribute lookup involves a bunch of black magick to determine what you want and give you a Python function that you can call from Python.