The following are a quick (random, off the top of various heads) list of things that I think are anti-pitfalls in Python. That is, because the language has these features, it is harder to make programming mistakes.
Thanks to Dougal, Anthony and Toby for running their eyes over this list, and for their suggestions.
- 1. Everything's a reference to an object (no magic line-noise)
Python doesn't have a separate scalar / reference syntax! Celebrate!
Dereferencing is one of the hardest concepts for a new programmer to learn, and I know from personal experience that some people gave up on the whole programming caper just because they didn't understand pointer arithmetic and dereferencing in C.
Aside: perhaps it might be because it's such a fundamental pitfall in other languages that people coming from them have such trouble coping with python's "names for objects" approach. How many times have we seen new Python programmers despairingly ask "how do I pass by reference"?
Pitfall avoided: Many and various errors due to not getting the magic line-noise quite right or not fully understanding the concept of dereferencing.
- 2. Real polymorphism
- (or rather, not that jumping-through-hoops, interface-tied,
type-casting-up-the-wazoo anticipate-all-use-cases polymorphism that some languages force on
Everything's an object and there's no built-in type checking on arguments. Interfaces generally evolve through consensus - if a function is written that accepts a file object argument to read data from, then any object that implements a read() method will do as a substitute argument - a StringIO instance, the result of a urllib.urlopen() call, a socket, etc.
Combine with built-in variable argument lists and keyword argument lists (with default values) for a really satisfying taste!
Pitfall avoided: Inflexibility due to not anticipating some new use of your code.
- 3. Sequence unpacking
I use it so much. Mostly just automatically too when returning
multiple values from a method/function. And "a,b = b,a" does the right
Pitfall avoided: Messy code.
- 4. The call operator
Bound methods, functions, classes... all use exactly
the same interface and all are first-class objects.
Pitfalls avoided: Having to deal with (and remember) the different ways of calling different callable things. Also, like #2 you don't have to worry about what kind of callable you might get if you accept one as a function argument.
- 5. Automatic memory management
Also under this heading could be the complete inability of user input to mangle code and take over your system (caveat: no use of exec/eval).
Pitfalls avoided: Memory usage going out of control. Your system being compromised because you didn't bounds-check some string from the Real World.
- 6. The print statement
A lot of other languages have a print statement or function but Python's is
particularly good at just dumping a bunch of information in human-readable
form. It just works. This is mostly because many/most builtin
objects have useful repr methods.
BTW, I think it's a good thing that it adds spaces, even with a dangling comma. If I want fine control over output, I'll use sys.stdout.write().
Pitfall avoided: Inability to just have a gander at what's going on.
- 7. Indentation for structure
Not only does this save typing, but it also means that code is far more
readable than in some other languages.
Pitfalls avoided: Unreadable code. Strange errors due to not using block delimeters when you should have used them.
- 8. Ubiquitous, unencumbering exception system
- It's available and used everywhere, and you don't have to trap exceptions if you don't want to. Trapping exceptions can be as fine-grained as you like, and you can send an arbitrary object of information along with the exception. Now that's nice.
- 9. Introspection
From Dougal: you can poke into any object. You can test whether objects
have attributes, or whether they're callable, or...
Pitfall avoided: Like #6, you can get in there to understand what's really going on in your own code.
- 10. Feature-full, rock-solid, simple built-in types
It can be argued that a lot of problems are averted just by having the
solid built-in string, tuple, list and dictionary types. The potential
problems in other languages being errors in
implementing those types or using half-assed attempts at implementing them.
Pitfall avoided: Half-assed basic type (re-)implementations.
- 11. No namespace pollution (unless you really want to)
Another from Dougal: Python doesn't automatically pollute namespaces unless
you specifically force it to with statements like "from foo import *".
Pitfall avoided: Namespace pollution, and the strange side-effects that occur.
- 12. The python shell (interactive interpreter)
From Toby: "if for no other reason than that i don't need a calculator
any more ;)". I definitely echo that sentiment, and more...
The interactive interpreter prompt lets new and experienced Python users
alike muck around with code to see what it does. I couldn't imagine
developing regular expressions without the interactive shell :)
Pitfall avoided: This is more a tool for avoiding a bunch of errors you might have run into without the ability to test ideas and code fragments out.
- 13. PDB
- From Anthony: PDB, the built-in debugger. I'm not sure this consitutes
an anti-pitfall, but it's definitely on his list. The magic string you're
looking for is "import pdb ; pdb.set_trace()"
When the code hits that you'll be dropped into the pdb shell. Nice.
Pitfall avoided: When things do go wrong, you've got the direct ability to get elbow-deep in the live program to see why it went wrong. And to change that live program then and there if necessary.
Pitfall avoided: Treating programmers like babies, asking them to be overly explicit in every little thing they do, and locking them out from things that they might hurt themselves on.