People love to pitch Python as a language to learn in. I am pretty sure this is because everything you hear about Python is about how easy and intuitive it is, and how people love to pitch it as a good choice for learning.
I have an alternative hypothesis: The Python community has become deeply committed to the notion that the way Python does things is by definition the most readable, cleanest, and otherwise best to learn. So that’s what gets talked about. People remember hearing about Python as a good teaching language, and as an easy language to learn.
I don’t think it’s actually a good language for teaching, and I frankly don’t think it’s a particularly clean or legible language. I’m by no means an expert Python programmer, but I have been reading and editing Python code on and off for some years now, and I’ve certainly learned a lot of other languages. I’ve also had the distinct pleasure of watching newbies encounter Python, and found that it’s not just that I’m biased because I know other languages; they are consistently being bitten by the same things I am.
A few specifics:
Indentation as flow control is not solving a real problem.
Yeah, I said it. I know, everyone loves to point to examples of C code in which what the code does and how it’s intended are mismatched. In Python, they gleefully explain, that can never happen, because the indentation is the flow control.
This sounds good, but in reality, I’ve been using C for something like twenty-five years, and in that time, I doubt I’ve seen two cases where there was an actual bug in which possible confusion between indentation and block structure could possibly have been involved. It isn’t actually a common problem.
In reality, the problem is almost never “I misunderstood that because the indentation misled me”. It’s “I did not correctly understand what the flow should have been”.
Python doesn’t help with that. At all. It doesn’t really make it any easier to see the flow of control. Worse is what happens when some editor mishap breaks things. In languages with explicit begin/end markers which are not inferred from indentation, you can tell that something has gone wrong. If you lose a token, the code stops compiling. If you merely screw up indentation, the fact that the indentation and flow control don’t match up tells you that something has gone wrong – it serves as a parity bit, in effect.
The net result is that, whether I’m looking at my Python code or other people’s, I find more flow control problems in the Python code than I do in C, lua, perl, Ruby, or sh. In all of those languages, the begin/end pairs are explicit, and in C, lua, and perl, they are consistently conducive to automated verification that they match, and editors can pop to the beginning or end of a block a little more reliably.
It’s super easy to read, except when it’s not.
Python has some lovely tools. Consider the “list comprehension”; a syntax for describing a list as code. For instance,
[x * x for x in range(10)] evaluates to the first ten squares. Easy to read, pretty. But of course, you might want to process only some of a list, in which case you get things like
[x * x for x in range(10) if x % 2 == 1]. Okay, that gets us the squares of the odd numbers from 1 to 10. But it’s not quite so readable anymore, because the condition is buried at the end of the operation.
Python tends to suffer from an initial dogmatic position that a particular thing is all that is needed, after which when more is needed, it has to be managed as an addition to that syntax rather than a change. So a lot of stuff gets sort of oddly inverted. Perfectly usable for an experienced programmer, but even fairly experienced programmers may find it a little confusing, and it’s certainly not novice-friendly.
Conventions are there to be violated.
Many programming languages have encountered a desire among users to be able to concatenate members of a list with some intervening text. In most object-oriented languages, this is viewed as an operation of the array or list object. So in Ruby, it’s something like
a.join(', '). Lua,
table.concat(a, ', '). Python, though, does
', '.join(a). Why? I have no idea. People give answers to that question, but none of the answers I’ve seen make any sense. I think it’s mostly just because if other languages do something, it’s presumed wrong because those languages aren’t Python, so Python does something different.
Even internally, it can be a bit hard to figure things out. A newbie friend was trying to use Python, and was stuck because of the behavior of Python class declarations. Which, of course, come in two types which are incompatible. Ugh.
Change is defeat.
Reactions by the Python community to suggested changes are rooted in a deep-seated emotional conviction that the language is correct, and if you don’t like it, you are wrong. There is a persistent cultural norm of condemning any suggestion that maybe the way Python does something isn’t as readable as something else. Python is defined as the most readable language; therefore, whatever Python is doing is maximally readable, and something else you would like is evidence that you are a bad person.
I have used many programming languages and tools. The only time I’ve ever had a user community insist that I ought to have total control over my corporate mail server and all the email servers I interact with, though, it was Python. See, a lot of mail servers break messages in various ways, usually harmless. But one common failure mode is screwing up empty space, especially at the beginning of lines. Is it super-common? No. But it happened to be affecting me for a while at work (we have no idea why, but I suspect a pathological interaction with the system that was trying to forward messages to a Blackberry), with the result that Python code sent to me not as a separate attachment was consistently garbled. I pointed out that this might be considered a way in which the indentation behavior could be inconvenient to users, and was basically told that it is idiotic for me to expect a programming language to survive any software which is broken in any way.
This is the general rule: Nothing is ever a problem with Python. Users who have trouble with it are derided. Tools or environments or requirements it doesn’t handle well are defective. And this, it turns out, means that things that might have gotten changed or addressed in another language are preserved, with ever greater emotional weight placed on believing that they are inherently superior, and rejecting as unworthy people who don’t like them.
Exceptions are the norm.
The heavy reliance on exception handling as the primary mechanism for everything is … unusual, anyway. In many other languages, the idiom is either that referencing an array or table produces a non-result if an item doesn’t exist, or that you check for existence before referencing. The Python idiom is that you reference the array unconditionally, which throws an exception if the requested item doesn’t exist. This idiom permeates things, and results in code which is quite simply a lot harder to read in most cases. Explicit tests may be clutter, but they’re clutter you can see. Exception handling is a
COME FROM; it’s a control object which isn’t visible at the point where control is transferred to it.
Yes, exception handling is good. It’s powerful. It is an extremely useful tool, and I think languages which have it gain significantly in expressiveness. But like many powerful tools, it’s harder to understand than many of the alternatives, can make it harder to track what really went wrong in code, and certainly makes a much more elaborate set of things to teach newcomers.
Not really trying to argue this comprehensively or anything, but… I do not think Python is a good teaching language. I do not think it is a particularly pretty, clean, or elegant language. It’s better than PHP, sure, but that’s not really saying much. Python does tend to be slightly more readable than perl, but that’s as far as I’d go. I consistently expect less effort reading either Lua or Ruby. C is often harder to read, but here we find the great failure of Python: You cannot write a code beautifier for it. C code can be reindented by software and most of the bad writing disappears immediately.
If you’re planning to make a thing for novice users, please don’t jump straight to Python because everyone says it’s the “easy” and “clean” language. It’s frankly not. I have seen nothing to indicate that Python produces particularly clean code, or is particularly easy to use, and I’ve seen a whole lot of people struggling with the language get harassed, insulted, and dismissed by members of the Python community.
Which is to say: The perception that the language is “easy to use” is rooted largely in driving away anyone who doesn’t find it easy to use. I’ve seen nothing to indicate that it’s really anything special. New users find it just as bewildering as other languages, and often moreso due to the mix between things intended to be simple and things intended to solve a problem that the simple thing didn’t solve.
Date: 2012-12-03 08:48:24 -0600
So out of curiosity, what language would you recommend as an introduction to programming? I’ve seen Ruby recommended frequently but have no experience with it myself.
From: Chris Walden
Date: 2012-12-03 10:58:59 -0600
So…. based on your experience, what WOULD you recommend as a teaching language?
Date: 2012-12-06 01:35:01 -0600
Those are interesting questions. For most users, I would probably pick either Lua or Ruby. Lua has the advantage that it’s embedded in a lot of video games, and “can use this to improve the way I play games” is a spectacularly good way to learn nearly anything.
Ruby is just plain pleasant to work with. It is not the language I am best at, but it is the language I am most likely to enjoy writing in.
From: Jack Maney
Date: 2012-12-10 02:41:01 -0600
Yes. This. In my previous job, I had to maintain some Python code, and I ran into what I coined The Python Uncertainty Principle: it is impossible to determine whether or not a text editor has garbled the tabs on a Python script until after the changes are saved and the script is run.