Some basic newbie questions...

Duncan Booth duncan.booth at invalid.invalid
Fri Dec 29 09:17:59 EST 2006


"jonathan.beckett" <jonathan.beckett at gmail.com> wrote:

> I'm just finding it a bit weird that some of the built in functions are
> static, rather than methods of objects (such as len() being used to
> find the length of a list).

When it comes down to it, its a design decision, so neither right nor wrong 
in itself. You need to look a bit wider than just 'len' to understand it.

There is the historical attribute: as I understand it, once upon a time, 
way back in the mists of time tuples didn't have methods at all, so you had 
to use a global function if you wanted to get the length of a tuple. That 
of course is no longer the case. However, ignoring for a moment that this 
may have been part of the reason why Python started in the direction of 
global helper functions, there are a lot of reasons why it turns out to 
have been a good decision.

Consider 'sum' for a moment. The function needs to know how to iterate over 
a sequence, but the sequence itself doesn't need to provide any support 
apart from iteration to be supported by 'sum'. If 'sum' was a method then 
you would have to implement it separately in every summable object; 
implement it in a common base class to all iterables; provide a 'Summable' 
mixin class requiring every designer of an iterable to decide at the outset 
whether they want it to be summable; or provide an adaptor class which 
takes an iterator and returns a summable iterator (which just adds a 
needless extra layer of complexity over the global function we started 
with).

'min', 'max', 'sorted', 'zip' are other functions which similarly provide 
support to any kind of iterable without encumbering the iterable protocol 
itself.

Next consider 'iter'. That's a global function which calls the __iter__ 
method, but it also has a fallback behaviour. Before Python had __iter__ 
iteration was define by calling __getitem__ with increasing index values, 
and if you don't have an __iter__ method the iter builtin will try the old 
protocol instead. So the global function has some more benefits: we can 
change the protocol it implements and continue to provide backward 
compatability, and we can have it do more than just calling the method 
which does the implementation.

getattr is another example of a builtin which appears to do the job of a 
method (__getattribute__) but actually does a whole lot more with fallback 
and exception handling in the function. Converting an AttributeError 
exception to a default value would be particularly nasty to get right if we 
were depending on a direct call to a base class __getattribute__ which 
might be overridden in the implemented class.

cmp is another good example: cmp(a,b) returns a.__cmp__(b), but if a 
doesn't have an __cmp__ method then it tries to return -b.__cmp__(a) (and 
has another fallback if even that fails).

There is also an argument that Python uses __ to distinguish internal 
implementation details so that the internal methods are effectively kept 
out of the user's namespace. The ordinary user shouldn't need to worry 
about the presence of __ methods as they never need to call them directly. 
In fact for beginners probably __init__ and "if __name__=='__main__':" are 
the only things besides 'keep off the double underscores' that they need to 
know about them.

So where does that leave 'len'? It is a function primarily for consistency 
with the general idea that you call a builtin (or a function imported from 
a support module) rather than calling a __ method directly. It does add 
some minimal functionality over calling __len__ directly, but not such that 
you'ld normally notice the difference.



More information about the Python-list mailing list