编写一个优雅的函数

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. 单一职责原则

参考:
提高代码质量:如何编写函数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容