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