1. 函数命名
- a. 能够精准的描述函数功能或行为,即采用准确的描述动词和名词。
- b. 尽可能完整的描述函数的行为,当函数无法完全遵循单一职责原则时,函数名应尽可能的描述函数的行为。
2. 函数参数
- a. 参数数量,不超过7个。函数参数数量越多,易用性越差、顺序越难以保证。
- b. 参数列表顺序,主要的、通用的参数在前面,次要的、关注低的参数在后面。
- c. bool类型参数,调用时尽量用带上参数名赋值,或者使用有意义的类枚举变量或常量代替无意义的bool值。原因:增强可读性。如:
delete_dvs(soft_delete=True) # 可读性更强
delete_dvs(True) # 不明白True的含义
- d.函数中不修改输入的参数,若修改无法避免,则必须文档注释说明。同时,即尽量不用输出参数。(使用输出参数,意味着函数不止做一件事情,可能会令调用者疑惑。可考虑分解函数,让函数只做一件事情)
3. 编写函数体
- a. 相关的语句和操作放在一起,即代码逻辑分段。一方面,各代码段逻辑独立,代码清晰;二方面,利于重购代码。比如:
# 修改前:
def calculateTotalPrice():
room_count = get_room_count()
meal_count = get_meal_count()
room_price= get_room_price(room_count)
meal_price = get_meal_price(meal_count)
return room_price + meal_price
# 修改后:
def calculateTotalPrice():
room_count = get_room_count()
room_price= get_room_price(room_count)
meal_count = get_meal_count()
meal_price = get_meal_price(meal_count)
return room_price + meal_price
修改前是先去获取房间数、早餐数,然后再去计算房间和早餐的价格。数目的获取和价格的计算相隔很远。修改后,分别以房间为单位计算价格,然后再以早餐为单位计算价格。当新增其他对象价格计算时只需在尾部追加即可,而无需前后两处均改动,当修改房间或早餐价格计算方法时也只需修改对应的代码块即可。
-
b. 尽量减少if、for代码嵌套层级
代码嵌套最好不超过2层。嵌套层级越深,阅读越困难。减少嵌套的技巧方法:
1. 尽早终止或返回数据。若符合某个条件时可以直接终止代码,则此条件应放在第一位。
# 反例:
if (condition1) :
if(condition2):
if(condition3):
pass
else:
return
else:
return
else:
return
# 修改后:
if(!condition1):
return
if(!condition2):
return
if(!condition3):
return
修改后代码明显比修改前逻辑清晰简洁了很多,阅读性也好很多。
2. 用map代替if语句分支(即表驱动法)
# 反例:
if condition == 'test1':
return 1
elseif condition == 'test2':
return 2
elseif condition == 'test3':
return 3
# 修改后:
map = {'test1': 1, 'test2': 2, 'test3': 3}
return map[condition]
修改前若新增一个分支,则需再加一个if判断。代码非常的冗长、低效,而且容易出错。
修改后,通过map将可变的数据和不变的流程分离,使得代码简洁、易于扩展。
3. 提取内层嵌套为一个函数进行调用
通过将内层嵌套提取为一个函数,令代码变得清晰简洁。
#例子:
for sub in subs:
network = None
for net in networks:
if sub['net_id'] == net['id']:
network = net
break
# 修改后:
def get_network(net_id, networks):
for net in networks:
if sub['net_id'] != net['id']:
continue
return net
for sub in subs:
network = get_network(sub['net_id'], networks)
修改后和修改前相比,代码需表达语义简洁明了,能够明确知道内循环是寻找sub的network。同时避免了代码头重脚轻。
而且后面需要修改获取network的方法时,也不会影响for的逻辑。
- c. for循环中不要执行重复代码,重复代码应在for之外只执行一次
#例子:
for sub in subs:
networks = list_network()
network = get_network(sub['net_id'], networks)
# 修改后:
networks = list_network()
for sub in subs:
network = get_network(sub['net_id'], networks)
相同的操作在for循序中重复执行,只会无谓的性能消化和降低效率。
- d. 提取复杂逻辑,语义化
对于一些复杂的逻辑,后面阅读代码代码的人通常搞不清在做什么。此时,应提取出这段复杂代码并函数化。
# 例子:
if (age > 18 && gender == 'man'):
doSth()
#修改后:
def canDoSth(age, gender):
return (age > 18 && gender == 'man')
if canDoSth(age, gender):
doSth()
修改后比修改前,语义清晰了很多,更易于阅读。
- e. 避免在函数中使用全局变量,原因:降低耦合性、提供可测试性(无需依赖全局变量)
4. 函数准则
- a. 单一职责原则
参考:
提高代码质量:如何编写函数