A foolish consistency, etc

People new (and not so new) to Python are often confused by the fact that the language uses functions in some situations, but methods in others. I see this come up a lot these days. The most recent example is this comment:

Say you have a list, how is a beginning supposed to follow/comprehend the bigger picture when faced with code like this:

mylist = [1,3,2]
print len( mylist )
print sorted( mylist )
print mylist.sort()
print mylist.reverse()
print mylist[0]

Honestly, what is going on here? Why different syntaxes for slightly different ideas?

This gives many people the feeling that OO in Python was added later, or "bolted on", as Taw puts it.

I figure the reasons for the discrepancy are like this:

In 1991, when Python was first released, *pure* object-oriented languages were rare. Sure, there was Smalltalk, but it was fairly obscure. Other languages that called themselves object-oriented, like C++ and ObjectPascal, were actually hybrids; objects were indeed "bolted on" to an existing language.

In this light, it makes sense that Python 0.9.1 did the same. It had built-in types, and user-defined objects. Some of the types, like lists and dictionaries, had methods, possibly because were mutable and therefore contained "state". Other types, like numbers, strings and tuples, did not have methods (and were therefore not "perceived" as objects, even though behind the scenes they were). (In fact, back in the early 90s, the idea of calling a method on a number seemed like a really odd idea (if you were not a Smalltalker :-).)

As a result, in order to take the length of a string or a tuple, you needed a *function* (because you could not call a method on these types). While list and dict could easily have had such a method, for consistency's sake this was omitted; instead, the len() function was to be used on them too.

And so it still is. But the world has changed since then. OO has become much more mainstream, and the notion of using methods for everything is no longer odd, but expected by many. I can understand why someone coming from Ruby (or maybe Java) would wonder why in some cases functions are required, where a method would seem more natural. It makes Python seem inconsistent, when initially the use of len() actually improved consistency.

This is something that *could* have been fixed in Python 3.0, but won't, as far as I understand it. I'm not sure if this is a missed opportunity, or that it will keep Python closer to its original spirit (i.e., a multi-paradigm language).

(Note: I am aware of the __len__ method of course, but honestly, who is really going to use that instead of len()? __len__ is a hook to make len() work, not an alternative for it.)

2 Comments »

  1. John Cowan said,

    June 19, 2008 @ 12:39 pm

    De facto len() is a method, in the sense that its behavior is polymorphic. It just can't be called with the syntax of a method, which is a wart, but what languages are without warts (except Scheme?)

  2. rgz said,

    June 19, 2008 @ 6:08 pm

    While I agree that python is being overly conservative and that list should have a length (and a join) method, the reason that Python sequences lack a length method is due to the fact that, length methods are so easy to create in an easy and standarised way that it really does not make sense to write a length method for every sequence ever and yet there is no way to make sure that every sequence will have a length method. Let me elaborate...

    One of the coolest methods in python is __getitem__ the reason it is so is because by overriding this hook and object gets access to special syntax like >>>item['retrieving'] and >>>for iterating in them: and also... length retrieving.

    I'm not gonna write it here but its fairly easy to write a __len__ method if an object supports __getitem__, its boilerplate code.

    And because it's boilerplate code, it got factored into the len() function.

    it would actually make more sense to factor this function as a method of some BaseSequence class and let the object inherit it from there but the function was easier to implement as a standalone function and so it was done that way. IT IS OLDSCHOOLED but in my opinion it doesn't illustrate that python isn't OO but that Python needed a Sequence base class and enforcing using that class and it failed to do so.

RSS feed for comments on this post

Leave a Comment