changed premature optimization example to something less argumentative
|Deletions are marked like this.||Additions are marked like this.|
|Line 123:||Line 123:|
|It is often useful to keep track of the index of an item in an iterable, for example, for reporting the line number of a string in a file. As of Python 2.3 the preferred way to do this is using the builtin enumerate instead of a manually updated count variable.||It is often useful to keep track of the index of an item in an iterable, for example, for reporting the line number of a string in a file. As of Python 2.3 the preferred way to do this is using the builtin enumerate instead of a manually updated count variable. (In versions of Python before 2.3,
this is actually not all that dubious... ;-)
This page follows a [http://groups.google.ca/groups?hl=en&lr=&selm=mailman.8378.1103832808.5135.python-list%40python.org&prev=/groups%3Fq%3Ddubious%2BFernando%26hl%3Den%26lr%3D%26group%3Dcomp.lang.python.*%26selm%3Dmailman.8378.1103832808.5135.python-list%2540python.org%26rnum%3D2 suggestion] of FernadoPerez on comp.lang.python. His suggestion was that there should somewhere be a collection of bad python practices together with an explanation of the badness and a preferred alternative. This seems a good job for a wiki-page, so ...
Premature Optimization is spending effort on execution efficiency before determining which parts of the code are actually significant to the program efficiency.
This occurs in a variety of contexts, all of which involve spending extra time making code run faster before first writing a simple, concise implementation that produces the correct results.
Example of over-optimizing attribute accesses:
While a correctly applied optimization can indeed speed up code, optimizing code that is only seldom used can waste significant development time, and can make code harder to read. Optimizations should only be sought when a programmer has isolated (using a profiler, etc.) a significant bottleneck in program efficiency. Write correct code first, then make it fast (if necessary).
Don't optimize until necessary.
Example of non-optimized but more readable attribute access:
String concatenation is building up a relatively lengthy string from a collection of strings.
Newcomers to Python often try to build strings up like this:
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
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, when we have
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.
(Please name me better!)
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.
There is a (very slight) speed of execution inefficiency in these examples. But much more important is the speed of entry and understanding inefficiency. All other things being equal, extra typing is evil. And, unless some 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!)
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.
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.
Counting Items without Enumerate
It is often useful to keep track of the index of an item in an iterable, for example, for reporting the line number of a string in a file. As of Python 2.3 the preferred way to do this is using the builtin enumerate instead of a manually updated count variable. (In versions of Python before 2.3, this is actually not all that dubious...
While timings are comparable, manual update is more verbose and has a greater risk of programming error if the programmer forgets to update the count variable.