Differences between revisions 1 and 11 (spanning 10 versions)
Revision 1 as of 2004-12-24 08:07:52
Size: 3706
Comment:
Revision 11 as of 2004-12-26 19:35:26
Size: 5343
Editor: DougRansom
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
DubiousPython 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 ...
Line 3: Line 3:
Following a suggestion (not yet linkable on google groups) of FernadoPerez on comp.lang.python, I am inaugurating this wiki page. Fernado's suggestion was that there should somewhere be a collection of bad python practices together with an explanation of the badness and a preferred alternative. As a hobbyist uni-lingual programmer, I can say that I'd certainly find such a resources useful. I can kick it off, but I'm afraid that I likely have more to offer on the dubious than the preferred side of the ledger. == Concern Over Efficiency ==
Effort expended on "execution inefficiency" when it is not a requirement of the end product being produced.
=== Dubious Way ===
Taking extra time or making code harder to read by writing code that is fast from the start, rather than getting the simplest, most readible thing working.
Line 5: Line 8:
Anyway, I thought it was a good idea, and a wiki page seems the best way to distribute the lifting. I'm hopeful this will get it started, but don't have any investment in the form or content of what is here; refactor at will. -- BrianvandenBroek example to join a bunch of strings together:
{{{
>>> print '%s%s%s%s%s' %tuple(string_list)
onebigstringinpieces}}}
}}}
Line 7: Line 14:
=== Preferred Way ===
Dead simple readible.

{{{#!python
>>> string_list = ['one', 'big', 'string', 'in', 'pieces']
>>> new_string = ""
>>> for s in string_list:
        new_string = new_string + s
>>> print new_string
onebigstringinpieces
>>>}}}
Line 14: Line 32:
{{{#!python
Line 15: Line 34:
>>> new_string = ""
>>> for s in string_list:
>>> new_string = "" 
>>> for s in string_list: 
Line 18: Line 37:

>>> print new_string
onebigstringinpieces
>>>
>>> print new_string 
onebigstringinpieces 
>>>}}}
Line 24: Line 42:
This is slow and resource heavy. Each time through the for loop, a new string is built and the old on 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. 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 Wiki:PrematureOptimization''
Line 28: Line 49:
For short cases where the number of strings to be joined is know, you can use string formatting as follows: For short cases where the number of strings to be joined is known, you can use string formatting as follows:
Line 30: Line 51:
{{{#!python
Line 31: Line 53:
onebigstringinpieces onebigstringinpieces}}}
Line 33: Line 55:
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 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
Line 38: Line 60:
{{{#!python
Line 39: Line 62:
onebigstringinpieces onebigstringinpieces}}}
Line 43: Line 66:
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, 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,
Line 45: Line 68:
{{{#!python
Line 46: Line 70:
oneJOINTbigJOINTstringJOINTinJOINTpieces oneJOINTbigJOINTstringJOINTinJOINTpieces}}}
Line 56: Line 80:
{{{#!python
Line 57: Line 82:
    # continue process     # continue process}}}
Line 61: Line 86:
{{{#!python
Line 65: Line 91:
        return False         return False}}}
Line 71: Line 97:
{{{#!python
Line 75: Line 102:
    return count > 10     return count > 10}}}
Line 78: Line 105:
== 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 ===
{{{#!python
dict(a=lambda x: str(x),
     b=lambda x: some_dict.get(x))}}}

=== 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 ===
{{{#!python
dict(a=str,
     b=some_dict.get)}}}

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 ...

Concern Over Efficiency

Effort expended on "execution inefficiency" when it is not a requirement of the end product being produced.

Dubious Way

Taking extra time or making code harder to read by writing code that is fast from the start, rather than getting the simplest, most readible thing working.

example to join a bunch of strings together:

>>> print '%s%s%s%s%s' %tuple(string_list)
onebigstringinpieces

}}}

Preferred Way

Dead simple readible.

   1 >>> string_list = ['one', 'big', 'string', 'in', 'pieces']
   2 >>> new_string = "" 
   3 >>> for s in string_list: 
   4         new_string = new_string + s
   5 >>> print new_string 
   6 onebigstringinpieces 
   7 >>>

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:

   1 >>> string_list = ['one', 'big', 'string', 'in', 'pieces']
   2 >>> new_string = "" 
   3 >>> for s in string_list: 
   4         new_string = new_string + s
   5 >>> print new_string 
   6 onebigstringinpieces 
   7 >>>

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

Preferred Alternatives

String Formatting

For short cases where the number of strings to be joined is known, you can use string formatting as follows:

   1 >>> print '%s%s%s%s%s' %tuple(string_list)
   2 onebigstringinpieces

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:

   1 >>> print "".join(string_list)
   2 onebigstringinpieces

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,

   1 >>> print 'JOINT'.join(string_list)
   2 oneJOINTbigJOINTstringJOINTinJOINTpieces

That said, some do consider this aspect of the join method of strings odd enough to count as a PythonWart.

Boolean Redundancy

(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.

Dubious Way

   1 if (count > 10) == True:
   2     # continue process

and

   1 def count_tester(count):
   2     if count > 10:
   3         return True
   4     else:
   5         return False

The Problem

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!)

Preferred Alternatives

   1 if count > 10:
   2     # continue process
   3 
   4 def count_tester(count):
   5     return count > 10

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

   1 dict(a=lambda x: str(x),
   2      b=lambda x: some_dict.get(x))

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

   1 dict(a=str,
   2      b=some_dict.get)

DubiousPython (last edited 2010-07-20 17:56:20 by 65-125-135-157)

Unable to edit the page? See the FrontPage for instructions.