对你的代码运行pylint
dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin
C0112
)和一个符号名(如empty-docstring
)来标识的. 在编写新代码或更新已有代码时对告警进行医治, 推荐使用符号名来标识.pylint \--list-msgs
来获取pylint告警列表. 你可以使用命令pylint \--help-msg=C6409
, 以获取关于特定消息的更多信息.pylint: disable-msg
, 本文推荐使用pylint: disable
. def foo(a, unused_b, unused_c, d=None, e=None):
_ = d, e
return a
仅对包和模块使用导入
import x
来导入包和模块.from x import y
, 其中x是包前缀, y是不带前缀的模块名.from x import y as z
,如果两个要导入的模块都叫做y或者y太长了.sound.effects.echo
可以用如下方式导入: from sound.effects import echo
...
echo.EchoFilter(input, output, delay=0.7, atten=4)
使用模块的全路径名来导入每个模块
# Reference in code with complete name.
import sound.effects.echo
# Reference in code with just module name (preferred).
from sound.effects import echo
允许使用异常, 但必须小心
像这样触发异常:raise MyException("Error message")
或者raise MyException
. 不要使用两个参数的形式(raise MyException, "Error message"
)或者过时的字符串异常(raise "Error message"
).
模块或包应该定义自己的特定域的异常基类, 这个基类应该从内建的Exception类继承. 模块的异常基类应该叫做"Error".
class Error(Exception):
pass
永远不要使用except:
语句来捕获所有异常, 也不要捕获Exception
或者StandardError
, 除非你打算重新触发该异常, 或者你已经在当前线程的最外层(记得还是要打印一条错误消息). 在异常这方面, Python非常宽容,except:
真的会捕获包括Python语法错误在内的任何错误. 使用except:
很容易隐藏真正的bug.
尽量减少try/except块中的代码量. try块的体积越大, 期望之外的异常就越容易被触发. 这种情况下, try/except块将隐藏真正的错误.
使用finally子句来执行那些无论try块中有没有异常都应该被执行的代码. 这对于清理资源常常很有用, 例如关闭文件.
当捕获异常时, 使用as
而不要用逗号. 例如
try:
raise Error
except Error as error:
pass
避免全局变量
鼓励使用嵌套/本地/内部类或函数
可以在简单情况下使用
Yes:
result = []
for x in range(10):
for y in range(5):
if x * y > 10:
result.append((x, y))
for x in xrange(5):
for y in xrange(5):
if x != y:
for z in xrange(5):
if y != z:
yield (x, y, z)
return ((x, complicated_transform(x))
for x in long_generator_function(parameter)
if x is not None)
squares = [x * x for x in range(10)]
eat(jelly_bean for jelly_bean in jelly_beans
if jelly_bean.color == 'black')
No:
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
return ((x, y, z)
for x in xrange(5)
for y in xrange(5)
if x != y
for z in xrange(5)
if y != z)
如果类型支持, 就使用默认迭代器和操作符. 比如列表, 字典及文件等.
# Yes:
for key in adict: ...
if key not in adict: ...
if obj in alist: ...
for line in afile: ...
for k, v in dict.iteritems(): ...
# No:
for key in adict.keys(): ...
if not adict.has_key(key): ...
for line in afile.readlines(): ...
按需使用生成器.
适用于单行函数
与语句相反, lambda在一个表达式中定义匿名函数. 常用于为map()
和filter()
之类的高阶函数定义回调函数或者操作符.
operator
模块中的函数以代替lambda函数. 例如, 推荐使用operator.mul
, 而不是lambda x, y: x * y
.适用于单行函数
x = 1 if cond else 2
.适用于大部分情况.
def foo(a, b = 0):
. 如果调用foo时只带一个参数, 则b被设为0. 如果带两个参数, 则b的值等于第二个参数. Yes: def foo(a, b=None):
if b is None:
b = []
No: def foo(a, b=[]):
...
No: def foo(a, b=time.time()): # The time the module was loaded???
...
No: def foo(a, b=FLAGS.my_thing): # sys.argv has not yet been parsed...
...
@property
装饰器创建的只读属性). 必须继承自object类. 可能隐藏比如操作符重载之类的副作用. 继承时可能会让人困惑.@property
[装饰器](http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Function_and_Method_Decorators) 来创建.# Yes:
import math
class Square(object):
"""A square with two properties: a writable area and a read-only perimeter.
To use:
>>> sq = Square(3)
>>> sq.area
9
>>> sq.perimeter
12
>>> sq.area = 16
>>> sq.side
4
>>> sq.perimeter
16
"""
def __init__(self, side):
self.side = side
def __get_area(self):
"""Calculates the 'area' property."""
return self.side <dt> 2
def ___get_area(self):
"""Indirect accessor for 'area' property."""
return self.__get_area()
def __set_area(self, area):
"""Sets the 'area' property."""
self.side = math.sqrt(area)
def ___set_area(self, area):
"""Indirect setter for 'area' property."""
self._SetArea(area)
area = property(___get_area, ___set_area,
doc="""Gets or sets the area of the square.""")
@property
def perimeter(self):
return self.side * 4
尽可能使用隐式false
if foo:
而不是if foo != []:
. 不过还是有一些注意事项需要你铭记在心:永远不要用==或者!=来比较单件, 比如None. 使用is或者is not.
注意: 当你写下if x:
时, 你其实表示的是if x is not None
. 例如: 当你要测试一个默认值是None的变量或参数是否被设为其它值. 这个值在布尔语义下可能是false!
永远不要用==将一个布尔量与false相比较. 使用if not x:
代替. 如果你需要区分false和None, 你应该用像if not x and x is not None:
这样的语句.
对于序列(字符串, 列表, 元组), 要注意空序列是false. 因此if not seq:
或者if seq:
比if len(seq):
或if not len(seq):
要更好.
处理整数时, 使用隐式false可能会得不偿失(即不小心将None当做0来处理). 你可以将一个已知是整型(且不是len()的返回结果)的值与0比较.
Yes: if not users:
print 'no users'
if foo == 0:
self.handle_zero()
if i % 10 == 0:
self.handle_mulle_of_ten()
No: if len(users) == 0:
print 'no users'
if foo is not None and not foo:
self.handle_zero()
if not i % 10:
self.handle_multiple_of_ten()
尽可能使用字符串方法取代字符串模块. 使用函数调用语法取代apply(). 使用列表推导, for循环取代filter(), map()以及reduce().
# Yes:
words = foo.split(':')
[x[1] for x in my_list if x[2] == 5]
map(math.sqrt, data) # Ok. No inlined lambda expression.
fn(*args, <dt>kwargs)
# No:
words = string.split(foo, ':')
map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))
apply(fn, args, kwargs)
推荐使用
def get_adder(summand1):
"""Returns a function that adds numbers to a given number."""
def adder(summand2):
return summand1 + summand2
return adder
sum = get_adder(summand1)(summand2)
) i = 4
def foo(x):
def bar():
print i,
# ...
# A bunch of code here
# ...
for i in x: # Ah, i *is* local to Foo, so this is what Bar sees
print i,
bar()
foo([1, 2, 3])
会打印1 2 3 3
, 不是1 2 3 4
.如果好处很显然, 就明智而谨慎的使用装饰器
my_decorator
, 下面的两段代码是等效的: class C(object):
@my_decorator
def method(self):
# method body ...
class C(object):
def method(self):
# method body ...
method = my_decorator(method)
pydoc
或其它工具导入). 应该保证一个用有效参数调用的装饰器在所有情况下都是成功的.不要依赖内建类型的原子性.
Queue
数据类型作为线程间的数据通信方式. 另外, 使用threading模块及其锁原语(locking primitives). 了解条件变量的合适使用方式, 这样你就可以使用threading.Condition
来取代低级别的锁了.避免使用这些特性