不使用 pythonic 的迴圈:
l = [1,2,3]
#Bad
for i in range(0,len(list)):
le = l[i]
print(i,le)
#Good
for i,le in enumerate(l):
print(i,le)
函式呼叫返回一個以上的變數型別
#Bad
def filter_for_foo(l):
r = [e for e in l if e.find("foo") != -1]
if not check_some_critical_condition(r):
return None
return r
res = filter_for_foo(["bar","foo","faz"])
if res is not None:
#continue processing
pass
#Good
def filter_for_foo(l):
r = [e for e in l if e.find("foo") != -1]
if not check_some_critical_condition(r):
raise SomeException("critical condition unmet!")
return r
try:
res = filter_for_foo(["bar","foo","faz"])
#continue processing
except SomeException:
#handle exception
迴圈永不終止
#example:
i = 0
while i < 10:
do_something()
#we forget to increment i
不使用 .iteritems() 遍歷 dict 的鍵/值對.
#Bad
d = {'foo' : 1,'bar' : 2}
for key in d:
value = d[key]
print("%s = %d" % (key,value))
#Good
for key,value in d.iteritems():
print("%s = %d" % (key,value))
不使用 zip() 遍歷一對列表
#Bad
l1 = [1,2,3]
l2 = [4,5,6]
for i in range(l1):
l1v = l1[i]
l2v = l2[i]
print(l1v,l2v)
#Good
for l1v,l2v in zip(l1,l2):
print(l1v,l2v)
Using "key in list" to check if a key is contained in a list.
This is not an error but inefficient, since the list search is O(n). If possible, a set or dictionary
should be used instead.
Note: Since the conversion of the list to a set is an O(n) operation, it should ideally be done only once when generating the list.
#Bad:
l = [1,2,3,4]
if 3 in l:
pass
#Good
s = set(l)
if 3 in s:
pass
在迴圈之後,不使用 'else'.
#Bad
found = False
l = [1,2,3]
for i in l:
if i == 4:
found = True
break
if not found:
#not found...
pass
#Good
for i in l:
if i == 4:
break
else:
#not found...
對於dict,不使用.setdefault()設定初始值
#Bad
d = {}
if not 'foo' in d:
d['foo'] = []
d['foo'].append('bar')
#Good
d = {}
foo = d.setdefault('foo',[])
foo.append(bar)
對於dict,不使用.get()返回預設值
#Bad
d = {'foo' : 'bar'}
foo = 'default'
if 'foo' in d:
foo = d['foo']
#Good
foo = d.get('foo','default')
使用map/filter而不是列表解析
#Bad:
values = [1,2,3]
doubled_values = map(lambda x:x*2,values)
#Good
doubled_values = [x*2 for x in values]
#Bad
filtered_values = filter(lambda x:True if x < 2 else False,values)
#Good
filtered_values = [x for x in values if x < 2]
不使用defaultdict
#Bad
d = {}
if not 'count' in d:
d['count'] = 0
d['count']+=1
#Good
from collections import defaultdict
d = defaultdict(lambda :0)
d['count']+=1
從一個函式中返回多個值時,不使用命名元組(namedtuple)
命名元組可以用於任何正常元組使用的地方,但可以通過name訪問value,而不是索引。這使得程式碼更詳細、更容易閱讀。
#Bad
def foo():
#....
return -1,"not found"
status_code,message = foo()
print(status_code,message)
#Good
from collections import namedtuple
def foo():
#...
return_args = namedtuple('return_args',['status_code','message'])
return return_args(-1,"not found")
ra = foo()
print(ra.status_code,ra.message)
不使用序列的顯式解包
支援解包的序列有:list, tuple, dict
#Bad
l = [1,"foo","bar"]
l0 = l[0]
l1 = l[1]
l2 = l[2]
#Good
l0,l1,l2 = l
不使用解包一次更新多個值
#Bad
x = 1
y = 2
_t = x
x = y+2
y = x-4
#Good
x = 1
y = 2
x,y = y+2,x-4
不使用'with'開啟檔案
#Bad
f = open("file.txt","r")
content = f.read()
f.close()
#Good
with open("file.txt","r") as input_file:
content = f.read()
要求許可而不是寬恕
#Bad
import os
if os.path.exists("file.txt"):
os.unlink("file.txt")
#Good
import os
try:
os.unlink("file.txt")
except OSError:
pass
不使用字典解析
#Bad
l = [1,2,3]
d = dict([(n,n*2) for n in l])
#Good
d = {n : n*2 for n in l}
使用字串連線,而不是格式化
#Bad
n_errors = 10
s = "there were "+str(n_errors)+" errors."
#Good
s = "there were %d errors." % n_errors
變數名包含型別資訊(匈牙利命名)
#Bad
intN = 4
strFoo = "bar"
#Good
n = 4
foo = "bar"
實現java風格的getter和setter方法,而不是使用屬性。
#Bad
class Foo(object):
def __init__(a):
self._a = a
def get_a(self):
return a
def set_a(self,value):
self._a = value
#Good
class Foo(object):
def __init__(a):
self._a = a
@property
def a(self):
return self._a
@a.setter
def a(self,value):
self._a = value
#Bad
def calculate_with_operator(operator, a, b):
if operator == '+':
return a+b
elif operator == '-':
return a-b
elif operator == '/':
return a/b
elif operator == '*':
return a*b
#Good
def calculate_with_operator(operator, a, b):
possible_operators = {
'+': lambda a,b: a+b,
'-': lambda a,b: a-b,
'*': lambda a,b: a*b,
'/': lambda a,b: a/b
}
return possible_operators[operator](a,b)
#Bad
class DateUtil:
@staticmethod
def from_weekday_to_string(weekday):
nameds_weekdays = {
0: 'Monday',
5: 'Friday'
}
return nameds_weekdays[weekday]
#Good
def from_weekday_to_string(weekday):
nameds_weekdays = {
0: 'Monday',
5: 'Friday'
}
return nameds_weekdays[weekday]