by leonardo maffi
Version 1.30, Jun 16 2011
Sometimes even good programmers at their first tries of Python use less than optimal solutions and language constructs. In the years Python has accumulated few redundancies and few warts (and some of them will be removed with Python 3.0. This article refers to CPython V.2.5, it's not about Python 2.6 yet, or about Jthon, or PyPy or IronPython, that may have subtle differences), but it's a generally clean language still, so with a page like this you can avoid the most common ones. This page hopes to be really simple and short enough, you can find explanations online elsewhere.
For some things I may be wrong, but this page comes from some experience, so when you don't agree with me, I suggest you to go look for the truth inside many newsgroups and Web pages, just don't assume you are right. If you find I am wrong, or you have questions or comments my email address can be found in my Home Page, I'll glady improve this page and learn from my mistakes.
[Go back to the index (email in the Home Page)]
|
Bad
|
Good
|
| x=5 if ( (x==8) and (y>5) ) : ... 1<<5&2 return(5); while (x<5) : ... 7. |
x
= 5 if x == 8 and y > 5: ... (1 << 5) & 2 return 5 while x < 5: ... 7.0 |
| print
x,x*x+1 v[i + 1 + a] + v[i + 2 + b] |
#
Sometimes rules can be broken, for # example to show grouping better: print x, x*x + 1 v[i+a+1] + v[i+b+2] |
| def Function ( x ): ... | def function(x): ... |
| class fooclass: ... | class Fooclass(object): ... |
| d = dict() | freqs
= {} # Descriptive names are often better # But in small scopes a short name may be fine |
| list
= [1, 2, 3] dict = {'alpha': 0x1234} sum = x + y |
# Don't shadow builtin names values = [1, 2, 3] symbol_address = {'alpha': 0x1234} tot = x + y |
| "some
string" and 'some string' and """some string""" and '''some string''' are the same string. |
|
| mapping = { 5 :"5", 6:"6" } | mapping = {5: "5", 6: "6"} |
| mapping
= {5 : "5", 6 : "6"} if mapping.has_key(6): ... |
mapping
= {5: "5", 6: "6"} if 6 in mapping: ... |
| def function( x, l = [] ): ... | #
Generally don't use mutables as a default def function(x, items=None): ... if items is None: items = [] |
| if x == None: ... | if x is None: ... |
| x
= 1 if z > 5: var1 = 55 |
#
Always use 4 spaces as indent # (Or always a Tab, but it's less good) x = 1 if z > 5: var1 = 55 |
| mapping
= {5 : "5", 6 : "6"} for key, val in mapping.items(): ... for key in mapping.keys(): ... |
#
Use iter* methods when possible mapping = {5: "5", 6: "6"} for key, val in mapping.iteritems(): ... for key in mapping: ... |
| for i in range(10, 20000): ... | for i in xrange(10, 20000): ... |
| #
Use to denote the code that has to # run when a module is executed and not # imported: if __name__ == '__main__': |
|
| #
Python profiler: python -m profile -o stats myscript.py >>> import pstats >>> p = pstats.Stats('stats') >>> p.sort_stats('time').print_stats(15) |
|
| For
source code with not 7-bit ASCII add this on top: # -*- coding: UTF-8 -*- # Or just, if you have less memory: # coding: latin |
|
| al
= [1, 2, 3] for i in xrange(len(al)-1, -1, -1): del al[i] |
items
= [1, 2, 3] del items[:] # But often if speed isn't critical you # can just use (but this is a different # thing, this creates a new list): items = [] # If you just want to remove one refence # to the list: del items |
| repeat xxx until yyy |
#
Equals to: while True xxx if yyy: break |
| #
To add a zip file containing modules # to the search path: sys.path.append("some.zip") |
|
| a
= 5 b = 6 aux = a a = b b = aux |
a
= 5 b = 6 a, b = b, a # swap |
| if x < 10 and x > 2: ... | if 2 < x < 10: ... |
| a
= 5 b = 5 c = 5 |
a = b = c = 5 |
| if
x == 1: y = fun1(x) else if x == 2: y = fun2(x) else if x == 3: y = fun3(x) else: y = None |
if
x == 1: y = fun1(x) elif x == 2: y = fun2(x) elif x == 3: y = fun3(x) else: y = None # But sometimes a dict is better: funs = {1: fun1, 2: fun2, 3: fun3} y = funs.get(x, lambda x:None)(x) |
| mapping
= {5 : "5", 6 : "6"} for key in mapping.iterkeys(): ... |
mapping
= {5: "5", 6: "6"} for key in mapping: ... |
| al
= [1, 2, 3] for i in xrange(len(al)): print al[i] |
al
= [1, 2, 3] for el in al: print el |
| al
= [1, 2, 3] for i in xrange(len(al)-1, -1, -1): print al[i] |
al
= [1, 2, 3] for el in reversed(al): print el |
| class
Test(object): def __init__(I, x): ... |
class
Test(object): def __init__(self, x): ... |
| #
Compute the sum of the ... def sum_of(x, y, z): ... |
def sum_of(x, y, z): ... """Compute the sum of the ...""" |
| from
operator import add sl = ["ab", "cd", "ef"] all = "" for s in sl: all += s # Or: sl = ["ab", "cd", "ef"] all = reduce(lambda x,y: x+y, sl, "") |
sl
= ["ab", "cd", "ef"] all = "".join(sl) |
| a
= "this isn't a word, right?" a = a.replace("'", " ") a = a.replace(".", " ") a = a.replace("?", " ") a = a.replace(",", "") |
#
.replace can be fine. This is faster: from string import maketrans tab = maketrans("'.?", " ") a = "this isn't a word, right." afilt = a.translate(tab, ",") |
| values = ["stop",0,0] | values = ["stop", 0, 0] |
| def
mul(x, y): return x*y l = [2, 3] print apply(mul, l) |
def
mul(x, y): return x * y l = [2, 3] print mul(*l) |
| vals
= [2, 3, -5, 0] result = [] for el in vals: if el > 0: result.append(el * el) |
vals
= [2, 3, -5, 0] result = [el * el for el in vals if el > 0] |
| l
= [0] * 4 m = [l] * 4 m[1][1] = 5 print m |
#
One correct way to create a matrix: m = [[0] * 4 for _ in xrange(4)] m[1][1] = 5 print m |
| a
= 1 print a / 2, a / float(2) |
#
A kind of alternative: from __future__ import division a = 1 print a // 2, a / 2 |
| class
Foo(object): def __init__(self, x, y, z): self.x_public = x self.y_private = y self.z_veryprivate = z def getx(self): return self.x_public print Foo(1, 2, 3).getx() |
# Generally getters
and setters are not used. |
| finder
= re.compile("^\s*([\[\]])\s*([-+]?\d+) \s*,\s*([-+]?\d+)\s*([\[\]])\s*$") |
finder
= re.compile(r""" ^ \s* # start at beginning+ opt spaces ( [\[\]] ) # Group 1: opening bracket \s* # optional spaces ( [-+]? \d+ ) # Group 2: first number \s* , \s* # opt spaces+ comma+ opt spaces ( [-+]? \d+ ) # Group 3: second number \s* # opt spaces ( [\[\]] ) # Group 4: closing bracket \s* $ # opt spaces+ end at the end """, flags=re.VERBOSE) # Sometimes it's positive to indent logically those # lines just like code. # Sometimes it can be positive to compose REs: spaces = r"\s*" # optional spaces number = r"( [-+]? \d+ )" # Group bracket = r"( [\[\]] )" # Group. Closing bracket parts = ["^", bracket, number, ",", number, bracket, "$"] finder = re.compile(spaces.join(parts), flags=re.VERBOSE) |
| def
function(data): """A comment""" ...implementation... |
#
Use doctests (or module tests): def function(data): """A comment >>>
function() if __name__ == "__main__": |
|
x = (1, 2, 6, 55, 63, 96, 125, 256, \ 301, 456, 958, 1256, \ 1359, 2568, 3597) |
x
= (1, 2, 6, 55, 63, 96, 125, 256, 301, 456, 958, 1256, 1359, 2568, 3597) # Too much long lines must be broken with \ # but \ isn't necessary inside () [] {} |
| from
Tkinter import * from mymodule import * |
import
Tkinter as tk from mymodule import fun1, Class1, baseconvert as bc |
| import
psyco psyco.bind(myfun1) a = [3.56, 2.12] |
try: import psyco # Psyco classes may be very useful from psyco.classes import __metaclass__ psyco.bind(myfun1) except ImportError: pass # Using psyco array.array of double and # signed long become very fast import array a = array.array("d", [3.56, 2.12]) # In some situations arrays of chars too are fast # psyco can be slow with itertools, map, filter # and generators, but fast with list # comprehensions. For max speed with Psyco # use low level coding style. |
| #
to print strings without spaces between: from sys import stdout stdout.write(string1) stdout.write(string2) |
|
| This
is good enough: words = ['me', 'do' 'bye', 'taz', 'foo', 'bar'] A shorter, more readable, but slower alternative: words = 'me do bye taz foo bar'.split() |
|
| #
sorting on the second item of the tuple # try to remove the i index from the temporary tuples lp = [(5J,"b"),(2J,"c"),(3+1J,"a"),(1+2J,"a")] lp2 = [(c, i, n) for i,(n, c) in enumerate(lp)] lp2.sort() print [(n, c) for (c, i, n) in lp2] |
from
operator import itemgetter lp = [(5J, "b"), (2J, "c"), (3+1J, "a"), (1+2J, "a")] print sorted(lp, key=itemgetter(1)) |
| vals
= [5, 7 ,8] tot = -2.0 for v in vals: tot += v |
vals
= [5, 7 ,8] tot = sum(vals, -2.0) |
| ll
= [[1, 2, 3], [4], [5, 6]] print sum(ll, []) |
data
= [[1, 2, 3], [4], [5, 6]] result = [] for sublist in data: result.extend(sublist) # Or even, for max speed from itertools import imap data = [[1, 2, 3], [4], [5, 6]] result = [None] * sum(imap(len, data)) pos = 0 for sublist in data: lensl = len(sublist) result[pos : pos+lensl] = sublist pos += lensl |
| print
"%s %s" % (string1, string2) print '"' + chr(c) + '":', freq[c] |
print
string1, string2 print '"%c": %d' % (c, freq[c]) |
| [' ', c][c.isalpha()] | #
For Python V.2.5+: (c if c.isalpha() else ' ') |
| #
How to invert string, lists, etc. alist[::-1] astring[::-1] |
|
|
# To negate (inplace) each second # element of alist: result = [] for (i, v) in enumerate(alist): # faster than i % 2 if i & 1 == 0: result.append(v) else: result.append(-v) alist[:] = result |
from operator import neg alist[1::2] = map(neg, alist[1::2]) # Or a bit slower but easier to read: alist[1::2] = [-el for el in alist[1::2]] |
| #
To shallow copy a list or dict: # (tuples don't need to be copied) newlist = list(alist) newdict = dict(adict) # Or just: newlist = list[:] |
|
| import
sys sys.exit() |
#
To stop a console program: raise SystemExit #Or just: exit() |
| if
type(s) == type(""): ... if type(seq) == list or \ type(seq) == tuple: ... |
if
isinstance(s, basestring): ... if isinstance(seq, (list, tuple)): ... # Or even: if hasattr(seq, "__getitem__"): ... # But quite often in dynamic languages you # don't test types, you just use them (look # for duck typing), catching exception that # may occur. |
| name1
= 5; name2 = 20; print name2 a = 1 b = 2 c = 3 |
name1
= 5 name2 = 20 print name2 a, b, c = 1, 2, 3 |
| prima
= 1 rossa = "Il colore rosso" léger = 30 |
#
English only for names: first = 1 red = "Il colore rosso" light = 30 |
| __del__
method of classes is usually left undefined. |
|
| try: fin = file("absent_file.txt") except: ... try: something() except: ... |
#
Generally specify what exception to catch: try: fin = file("absent_file.txt") except IOError: ... try: something() except someException: ... |
| except ImportError, IOError: ... | except (ImportError, IOError): ... |
| bytes
= array.array('B', [0] * nbytes) # Or: from itertools import repeat bytes = array.array('B', repeat(0, nbytes)) |
#
This can be much faster bytes = array.array('B', [0]) * nbytes |
| freqs
= {} for c in "abracadabra": try: freqs[c] += 1 except: freqs[c] = 1 |
#
Short way: freqs = {} for c in "abracadabra": freqs[c] = freqs.get(c, 0) + 1 # Often the fastest way: freqs = {} for c in "abracadabra": if c in freqs: freqs[c] += 1 else: freqs[c] = 1 # Or better with Python 2.5+: from collections import defaultdict freqs = defaultdict(int) for c in "abracadabra": freqs[c] += 1 |
|
someitems = set([1,
2, 3]) |
someitems
= set([1, 2, 3]) somemap = {1: 2, 3: 4, 5: 6} print iter(someitems).next() print iter(somemap).next() |
| from time import clock | #
This works well on Windows and Linux: from timeit import default_timer as clock # Or often use the timeit module |
I have to thank many people for suggestions and spotting typos. Thanks to Mark Dufour for fixing few errors, Francesco Brasini for another bug spotted, and Ludvig Ericson for more suggestions/problems found. Another little bug was spotted by pkrumins and Thijs Blaauw. A typo spotted by d0mine. A couple suggestions by attack. Alternative regular expression suggested by ken. A suggestion by greml1n. Two suggestions by arn.zart. Fixed an HTML coversion error found by Olivier Laurent. Typo found by Paolo Orru'. Typo found by Almog Melamed.
See PEP 8 too for more style guides for Python code: http://www.python.org/dev/peps/pep-0008/
[Go back to the index (email in the Home Page)]