Riddle me this: does Python have lexical scope, closures, useful built-in data-types, familiar syntax, functions, variables, looping constructs, or objects?

Before I get started, I invite a Perl advocate to answer the same set of questions for Perl so we can all compare. Any volunteers?

OK, here goes:

  • Lexical scope: kinda, sorta. Truth be told, Python scope is neither truly lexical nor truly dynamic. It is, however, well documented and easy to understand; see this post and the pointers therein for a better explanation. Short form: the language generally tends more toward lexical than dynamic, and is certainly evolving even further in that direction
  • Closures: not as such, but there’s a very standard trick involving lambda default arguments that gives the same effect without requiring an extension to the language.
  • Useful built-in data types: damn right! Lists, dictionaries, objects, you name it.
  • Functions, variables, looping constructs: yes, yes, and yes. Also a nice exception system.
  • Objects: absolutely. A well-designed set of interactions between objects, dictionaries and namespaces is at the very core of Python. OO is not just something bolted on to Python after the fact; it has been there since day one, and it’s almost impossible to write any non-trivial program without using objects.

Before we go on, I’d also like to touch on two things about Python that you didn’t even ask about but that help make it even cooler.

  • Python maintains a good separation between language and environment. A lot of stuff that clutters up A Certain Other Language is in libraries with Python, often using much nicer object-based interfaces. This makes things much more portable, extensible, etc.
  • The ability to extend Python with modules written in C, using a well-documented API, should not be underestimated. This aspect of the language is, again, not an afterthought. As with Tcl, extensibility and embeddability (something with which I personally have less experience) were design goals from Day One. Time-machine references aside, this is what happens when you design stuff well to start with. Extensions have been written that I’m sure Guido van Rossum could never have imagined when he was designing Python, but because he followed good design processes they were easy to create.

Next question:

How does it help you manage a program better than, say, Perl?

I have to admit that it’s hard for me to put some of this into words, because it has to do with general philosophy rather than specific features. A lot of what’s in Python is there specifically to improve clarity, reduce possibility for error, etc. Sometimes Guido has arguably gone too far, such as with the indentation thing or long-standing (but finally overcome) opposition to augmented assignment, but it’s hard to fault him for that. He knows what he’s doing, and so do the other decision-makers. Despite quibbles from Perl or Scheme folks who are surprised by anything not Perl or Scheme, Python generally follows the “principle of least surprise” rather well.

The fact that objects are central and not just peripheral to Python is one example of something that has far-reaching but hard to define consequences. The fact that it has had mature module and exception features from the start is similarly helpful, especially in larger programs. Object-persistence stuff like pickle and shelve (yeah, weird names), rudimentary as they may seem, have also proven invaluable to many people. One might say that Perl has caught up in many of these areas, though I personally think it still has a way to go, but catching up is still not the same as doing it right the first time. Legacy code written “before we had X” is a pain.

What does it *not* let you do that you might conceivably want to do, and how ugly are the methods used to get around this?

Damn little. A lot of people have done a lot of very fancy things with Python. There’s very little you can’t do even if you only use the language in the most straightforward way. If that doesn’t work, you can step into meta-object programming and namespace manipulation, which are a little bit tricky but still not “black magic”. If that doesn’t work you can write an extension module, which again is about as painless as one could reasonably expect it to be. Overall, whatever level you have to go to, it’s about as non-ugly as one could hope for. The only time I had to do something really ugly in a Python program was when I had to deal with some issues about default parameters being evaluated at function-definition rather than function-call time.

In a post of this length, I would of course be remiss if I didn’t mention some of the things that I think are wrong with Python. Bear in mind, though, that I’m loth to gainsay the language developers’ decisions even when I might have done it differently myself. They have done a better job than I would have.

  • I live with the indentation thing, but I’m among those who would be at least half an iota happier if Python used braces.
  • The fact that certain built-in types are not true objects is suboptimal (this is improving).
  • Not being able to subclass extension-module objects sucks. You can get around it by creating a Python class to wrap the C class, but that is kind of kludgy. In general, some of the internal relationships between objects, classes, and namespaces could be improved.
  • Some nitpicky details about lists/tuples/slices have never felt right to me. This is definitely a matter of personal taste; most people would probably hate the way I’d do it.
  • Some of the newer package stuff seems a little baroque to me, but it’s still evolving, so who knows?