声明:摘自Code Style
如果你问一个Python程序员他最喜欢Python里的什么,他通常会说高可阅读性。事实上,便于阅读是Python语言设计的核心,这是基于这样一个事实,阅读代码通常比写代码的时候多。
Python代码利于阅读的一个原因是它有一个相对完善的代码风格指南和“Pythonic“原语。
当一个Python老鸟指着一块代码说不够“Pythonic”的时候,通常意味着这段代码没有遵守公共的规范,并且没有用最好的方式表达内在的意图。
在一些例子里,怎样用Python代码来表达一个意图,并没有一致认同的最好的方式。但是,这种例子是很少见的。
精确的代码
当有好多黑魔法可用的时候,最精确直接的方式是首选。
Bad
def make_complex(*args):
x, y = args
return dict(**locals())
Good
def make_complex(x, y):
return {'x': x, 'y': y}
好代码中,接受了x,y并返回一个字典。使用这个函数的开发者通过首尾两行代码很容易就知道怎样使用。
一行一条语句
一些复合语句如list comprehensions可打破此例,但把两条不相关的语句写在一行里则是差的实践。
Bad
print 'one'; print 'two'
if x == 1: print 'one'
if <complex comparison> and <other complex comparison>:
# do something
Good
print 'one'
print 'two'
if x == 1:
print 'one'
cond1 = <complex comparison>
cond2 = <other complex comparison>
if cond1 and cond2:
# do something
函数参数
向一个函数传递参数有四种方法。
-
Positional arguments是必选参数并且没有默认值。这是最简单的一种参数形式,可以用在参数是函数的全部意思并且参数顺序是自然的。例如在send(message, recipient)或者point(x, y)中,用户很容易记住这两个参数和顺序。
在这两个例子里,使用参数名调用也是可以的,甚至还可以改变顺序,如send(recipient='World', message='Hello')或point(y=2, x=1),但是和前一种方法相比,降低了可读性而且变得冗长。
-
Keyword arguments是可选参数并且有默认值。当一个函数有两或三个positional 参数时,函数会变得很难记忆,用keyword参数会有所改善。例如一个更复杂的send函数,send(message, to, cc=None, bcc=None)。这里cc和hcc是可选的,并且当没有传入参数是会赋值为None。
可以通过多种方式调用一个有keyword参数的函数。例如,不使用参数名send('Hello', 'World', 'Cthulhu', 'God'),改变参数顺序send('Hello again', 'World', bcc='God', cc='Cthulhu'),但是没有特别原因最好还是使用这种接近函数定义的方式send('Hello', 'World', cc='Cthulhu', bcc='God')。
一些可选参数为了以防万一但是看起来好像永远不会用到,按照YAGNI原则,删除可选参数要比添加一个可选参数更困难。
-
arbitrary argument list是第三种参数形式。当一个函数的意图可以通过任意个positional参数更好表达时,可以使用args构造。在函数体内,args会是包含所有positional参数的元组。例如send(message, args)可以这样调用send('Hello', 'God', 'Mom', 'Cthulhu'),在函数体内args等同于('God', 'Mom', 'Cthulhu')。
在这里定义成这样更好send(message, recipients),调用的时候传入一个列表send('Hello', ['God', 'Mom', 'Cthulhu'])。
-
arbitrary keyword argument dictionary是第四种方法。
返回值
def complex_function(a, b, c):
if not a:
return None # Raising an exception might be better
if not b:
return None # Raising an exception might be better
# Some complex code trying to compute x from a, b and c
# Resist temptation to return x if succeeded
if not x:
# Some Plan-B computation of x
return x # One single exit point for the returned value x will help
# when maintaining the code.
Idioms
-
Unpacking
for index, item in enumerate(some_list): # do something with index and item a, b = b, a a, (b, c) = 1, (2, 3)
-
Create an ignored variable
filename = 'foobar.txt' basename, __, ext = filename.rpartition('.')
-
Create a length-N list of the same thing
four_nones = [None] * 4
-
Create a length-N list of lists
four_lists = [[] for __ in xrange(4)] letters = ['s', 'p', 'a', 'm'] word = ''.join(letters) d = {'s': [], 'p': [], 'a': [], 'm': []} l = ['s', 'p', 'a', 'm'] def lookup_dict(d): return 's' in d def lookup_list(l): return 's' in l
PEP8
检测代码是否符合PEP8规范
pip install pep8
约定
-
检测变量
Bad:
if attr == True: print 'True!' if attr == None: print 'attr is None!'
Good:
# Just check the value if attr: print 'attr is truthy!' # or check for the opposite if not attr: print 'attr is falsey!' # or, since None is considered false, explicitly check for it if attr is None: print 'attr is None!'
-
访问Dict元素
Bad:
d = {'hello': 'world'} if d.has_key('hello'): print d['hello'] # prints 'world' else: print 'default_value'
Good:
d = {'hello': 'world'} print d.get('hello', 'default_value') # prints 'world' print d.get('thingy', 'default_value') # prints 'default_value' # Or: if 'hello' in d: print d['hello']
-
操作List
Bad:
# Filter elements greater than 4 a = [3, 4, 5] b = [] for i in a: if i > 4: b.append(i)
Good:
b = [i for i in a if i > 4] b = filter(lambda x: x > 4, a)
Bad:
# Add three to all list members. a = [3, 4, 5] count = 0 for i in a: a[count] = i + 3 count = count + 1
Good:
a = [3, 4, 5] a = [i + 3 for i in a] # Or: a = map(lambda i: i + 3, a) for i, item in enumerate(a): print i + ", " + item # prints # 0, 3 # 1, 4 # 2, 5
-
读取文件
Bad:
f = open('file.txt') a = f.read() print a f.close()
Good:
with open('file.txt') as f: for line in f: print line
-
换行
Bad:
my_very_big_string = """For a long time I used to go to bed early. Sometimes, \ when I had put out my candle, my eyes would close so quickly that I had not even \ time to say “I’m going to sleep.”""" from some.deep.module.inside.a.module import a_nice_function, another_nice_function, \ yet_another_nice_function
Good:
my_very_big_string = ( "For a long time I used to go to bed early. Sometimes, " "when I had put out my candle, my eyes would close so quickly " "that I had not even time to say “I’m going to sleep.”" ) from some.deep.module.inside.a.module import ( a_nice_function, another_nice_function, yet_another_nice_function)
其他资源
- http://c2.com/cgi/wiki?ProgrammingIdiom
- http://stackoverflow.com/questions/302459/what-is-a-programming-idiom
- http://stackoverflow.com/questions/513882/python-list-vs-dict-for-look-up-table
- http://stackoverflow.com/questions/228181/zen-of-python
- http://artifex.org/~hblanks/talks/2011/pep20_by_example.pdf