This page follows a suggestion of FernadoPerez on comp.lang.python that there should be a collection of bad python practices together with an explanation of the badness and a preferred alternative.
Contents
String Concatenation
String concatenation is building up a relatively lengthy string from a collection of strings.
Dubious Way
Newcomers to Python often try to build strings up like this:
The Problem
This is slow and resource heavy. Each time through the for loop, a new string is built and the old one is discarded. That might not matter so much for such a small case, but as the number of elements to be joined creeps up, so too does the inefficiency.
The above code is perfectly fine. Its readible, and it works. Worrying about speed/performance when it is not an issue is one of the worst programming practices. "Premature Optimization is the Root of All Evil" -- see PrematureOptimization
Training yourself to NEVER use some possibly-tempting idiom that is NEVER right is not premature: JUST SAY NO, learn to see this way to build up strings as ugly and always wrong, and live happily ever after!
If we are going to quote Knuth: The conventional wisdom shared by many of today's software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by pennywise-and-pound-foolish programmers, who can't debug or maintain their "optimized" programs. In established engineering disciplines a 12 % improvement, easily obtained, is never considered marginal; and I believe the same viewpoint should prevail in software engineering.
From the same paper (Structured Programming with go to Statements) that he stated: We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3 %. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code;
Preferred Alternatives
String Formatting
For short cases where the number of strings to be joined is known, you can use string formatting as follows:
This is much more efficient, but is also rather more limited in the range of circumstances to which it applies. It could be made more general by constructing the formatting string as a function of len(string_list), but this would be a bit dubious, too. It's also less readible, less maintainible. A better alternative is found in the next section.
The join method of strings
The join method of the string type lets you perform the concatenation as follows:
This is quite efficient and perfectly general as it applies to any arbitrary list of strings. (You don't need to know the list length in advance.)
The major thing to puzzle the newcomer here is why "".join(some_list) rather than some_list.join(). The way to think of this is that you are using the string "" to join the elements of some_list. Hence,
That said, some do consider this aspect of the join method of strings odd enough to count as a PythonWart.
If the ''.join(some_list) syntax really bothers you, one option is to bind the method to a different name, e.g.
The audience should be an expert in the idioms of a language when considering readability. The join is simple to this crowd.
Overly Verbose Conditionals
Among the most common tasks in programming is to test if a condition obtains and act accordingly. It is common for newcomers to Python to adopt an all-together overly verbose idiom for this.
Dubious Way
The Problem
There is a slight speed of execution inefficiency in these examples. The first example has the overhead of an extra method lookup (bool.__eq__) and an extra name lookup (True). The second example has the overhead of an extra branch statement. The third example has the overhead of two extra method lookups (somecontainer.__len__ and int.__cmp__).
But much more important is the speed of entry and understanding inefficiency. All other things being equal, extra typing is evil. And, unless some substantial gain in clarity is purchased by the extra characters, the more characters in the code, the longer that code will take to understand. (The programming time you save could well be your own!)
Preferred Alternatives
Most non-empty containers evaluate to True in a boolean context, so no test on len() is generally necessary:
Some containers (e.g. numarray.array) do not evaluate this way. In these cases, the preferred idiom is:
Overuse of lambda
Lambda forms allow anonymous functions to be created and used as part of an expression. However, when a function is already named, wrapping this function in a lambda can decrease readability and affect program efficiency.
Dubious Way
The Problem
Using a lambda when a function is already named incurs the extra overhead of one function call, which is generally undesirable as function calls are relatively expensive in Python. Even setting execution efficiency aside, the lambda-less versions are preferred because they are generally more concise and easier to read.
Preferred Alternatives
Inappropriate use of Lambda
There are situations where the usage of Lambda is completely inappropriate. The most inappropriate usage is where a lambda is used to create a named function. Especially when that named function uses recursion.
