代码可读性
原则
函数
规范的命名
# bad
def getknn(from_df):
#good
def k_nearest_neighbors(dataframe):- “get”这个词是无关紧要的。对于大多数命名比较好的函数来说,很明显有一些东西会从函数中返回,它的名字将反映这一点。
- from_df 也不是必要的。如果没有明确的参数名称,函数的文档字符串或类型注释会描述参数的类型。
单一功能
def calculate_and print_stats(list_of_numbers):
# 计算
sum = sum(list_of_numbers)
mean = statistics.mean(list_of_numbers)
median = statistics.median(list_of_numbers)
mode = statistics.mode(list_of_numbers)
# 打印
print('-----------------Stats-----------------')
print('SUM: {}'.format(sum) print('MEAN: {}'.format(mean)
print('MEDIAN: {}'.format(median)
print('MODE: {}'.format(mode)很明显这个函数兼顾了两个不同类型的功能,这里就应该将这个函数进行一个按照功能类型的分构,写成两个独立的函数。
每个函数都需要有一个文档字符串
使用适当的语法和标点符号;用完整的句子写
首先对函数的作用进行一句话的总结
使用说明性语言而不是描述性语言
函数的长度不应太长,行数控制在150行以内最好
高可读个案例
代码行数越少,并不意味着越好,代码的质量应该以可读性来衡量
变量交换
tmp = a
a = b
b = tmp
a,b = b,a
列表推导
my_list = []
for i in range(10):
my_list.append(i*2)
my_list = [i*2 for i in range(10)]
优化单行表达式
print('hello'); print('world')
if x == 1: print('hello,world')
if <complex comparison> and <other complex comparison>:
# do something
print('hello')
print('world')
if x == 1:
print('hello,world')
cond1 = <complex comparison>
cond2 = <other complex comparison>
if cond1 and cond2:
# do something
带索引遍历
- 低效的做法
for i in range(len(my_list)):
print(i, "-->", my_list[i])
- 高效的做法
l = len(my_list)
for i in range(l):
print(i, "-->", my_list[i])
- 注重可读性的做法
for i,item in enumerate(my_list):
print(i, "-->",item)
如果需要对大量数据进行操作(10万,百万级别)建议采用高效的方式,如果是普通业务遍历,建议采用注重可读性的方式
序列解包
a, *rest = [1, 2, 3]
# a = 1, rest = [2, 3]a, *middle, c = [1, 2, 3, 4]
# a = 1, middle = [2, 3], c = 4
字符串拼接
letters = ['s', 'p', 'a', 'm']
word = ''.join(letters)
真假判断
除了使用了True
、 False
、 None
判断布尔值,还可以使用
# False
if "":
if []:
if {}:
# True
if not "":
if not []:
if not {}:
访问字典元素
当直接使用 []
来访问字典里的元素时,若key不存在,是会抛异常的,所以新会可能会先判断一下是否有这个 key,有再取之。
tar = {'hello': 'world'}
key = "hello"
if tar.has_key(key):
print(d[key])
else:
print('default_value')
if key in tar:
print(d[key])
else:
print('default_value')
- 优化
tar = {'hello': 'world'}
key = "hello"
print(d.get(key, 'default_value'))
操作列表
下面这段代码,会根据条件过滤过列表中的元素
a = [3, 4, 5]
b = []
for i in a:
if i > 4:
b.append(i)
以使用列表推导或者高阶函数 filter 来实现
a = [3, 4, 5]
b = [i for i in a if i > 4]
# Or:
b = filter(lambda x: x > 4, a)
除了 filter 之外,还有 map、reduce 这两个函数也很好用
a = [3, 4, 5]
b = map(lambda i: i + 3, a)
# b: [6,7,8]
文件读取
文件读取是非常常用的操作,在使用完句柄后,是需要手动调用 close 函数来关闭句柄的
fp = open('file.txt')
print(fp.read())
fp.close()
如果代码写得太长,即使你知道需要手动关闭句柄,却也会经常会漏掉。因此推荐养成习惯使用 with open
来读写文件,上下文管理器会自动执行关闭句柄的操作
with open('file.txt') as fp:
for line in fp.readlines():
print(line)
代码续行
将一个长度较长的字符串放在一行中,是很影响代码可读性的(下面代码可向左滑动)
long_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.”'
稍等注重代码可读性的人,会使用三个引号 \
来续写
long_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.”'
使用括号包裹 ()
long_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
)
使用占位符
对于暂不需要,却又不得不接收的的变量,请使用占位符
filename = 'foobar.txt'
basename, _, ext = filename.rpartition('.')
_,ext = path.splitext(filename)
链式比较
score = 85
if score > 80 and score < 90:
print("良好")
- 更好的写法
score = 85
if 80 < score < 90:
print("良好")
三目运算
对于简单的判断并赋值
age = 20
if age > 18:
type = "adult"
else:
type = "teenager"
其实是可以使用三目运算,一行搞定。
age = 20
b = "adult" if age > 18 else "teenager"