前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >程序猿应该如何写好一个函数

程序猿应该如何写好一个函数

作者头像
明月AI
发布2021-10-28 14:48:00
发布2021-10-28 14:48:00
39200
代码可运行
举报
文章被收录于专栏:野生AI架构师野生AI架构师
运行总次数:0
代码可运行

在review同事的代码时,发现一些代码的坏味道,先看一段代码:

代码语言:javascript
代码运行次数:0
复制
def get_merge_cell_rows_cols_num(one_table_data, df, List, flag):
    '''
    整合单元格所占行数,列数
    :param one_table_data: 单表格
    :param df: 二维数组
    :param List: 位置列表
    :param flag: 合并了的行列标志
    :return:
    '''
    first_location = List[0] if List else []
    cell_row = []
    cell_column = []
    for location in List:
        if first_location[0] == location[0]:
            cell_column.append(location[1])
        if first_location[1] == location[1]:
            cell_row.append(location[0])
    for index_r, rows in enumerate(df):
        for index_h, i in enumerate(rows):
            if i == flag:
                one_table_data[index_r][index_h]["rows"] = cell_row
                one_table_data[index_r][index_h]["cols"] = cell_column
                break

下面逐一总结一下其中的坏味道。

函数应该保持幂等性


函数是系统的元组件,组件要是写不好,整个系统的技术债就算是欠下了。而保持幂等性是系统可读性和可维护性的关键一环,关于幂等性,看这里,或者点击查看原文。

在代码中,传入了一个多维数据one_table_data,但是在函数里面修改了其中的值,这样整个函数就没法保持幂等性了,再调用一次的时候,参数就已经被修改了,这就产生了不可预测性。这时,外部调用了人就需要知道函数的实现逻辑,才能知道产生了什么副作用,可读性就降低了,出问题也比较难调戏。

就这个函数而言,修改一下就能保持幂等性,直接将21-23行修改一下就能完成:

代码语言:javascript
代码运行次数:0
复制
return index_r, index_h, cell_row, cell_column

这时,函数也可以少传入一个参数one_table_data,参数越少,可读性往往越好。影响幂等性的情况,除了函数参数,通常还有:

  • 全局变量:不是不可以使用,而是应该尽量减少其使用,特别是不应该在函数中修改全局变量的值。
  • 类属性和实例属性:使用的时候,也应该要注意。

不过,并不是所有函数都可以实现幂等性的,不能为了幂等性而幂等性。

变量取名的艺术


其实谈不上艺术,只是很多人在变量命名上确实很具迷惑性。

例如函数参数中的df, List, flag这三个参数太泛了,但看变量名很难看出更多的信息,必须得结合注释或者具体的实现才能理解其含义。这里还有一个大小写的问题,在python中习惯上,通常都是使用小写单词作为变量名,不应该混用命名方式。

单复数问题也是变量名中常见的,例如:cell_row和cell_column,这两个在定义上都是一个列表,命名上应该是复数的形式,如:cell_rows, cell_cols。(这里将column缩写成了col,这是常用的缩写,刚好缩写完之后和row就都是三个字符了。当然,缩写轻易不应该使用,可能会影响可读性)

还有第19行的代码:

代码语言:javascript
代码运行次数:0
复制
for index_h, i in enumerate(rows)

这行代码看着会很迷惑,因为变量ijk之类的,通常是用于循环中的下标,而不是值,而且变量i是什么意思呢。

减少代码的缩进层数


代码中体现不多,不过也是可以优化的,函数中的两个循环体都是可以优化的,例如第一个循环体:

代码语言:javascript
代码运行次数:0
复制
    cell_row = []
    cell_column = []
    for location in List:
        if first_location[0] == location[0]:
            cell_column.append(location[1])
        if first_location[1] == location[1]:
            cell_row.append(location[0])

使用推导式,可以让代码很简洁:

代码语言:javascript
代码运行次数:0
复制
cell_rows = [loc for loc in List if first_location[0] == loc[0]]
cell_columns = [loc for loc in List if first_location[1] == loc[1]]

对于第二个循环体:

代码语言:javascript
代码运行次数:0
复制
    for index_r, rows in enumerate(df):
        for index_h, i in enumerate(rows):
            if i == flag:
                one_table_data[index_r][index_h]["rows"] = cell_row
                one_table_data[index_r][index_h]["cols"] = cell_column
                break

可以改为:

代码语言:javascript
代码运行次数:0
复制
    for index_r, rows in enumerate(df):
        for index_h, i in enumerate(rows):
            if i == flag:
                continue
            one_table_data[index_r][index_h]["rows"] = cell_row
            one_table_data[index_r][index_h]["cols"] = cell_column
            break

在一个函数内部,缩进嵌套太多是很影响可读性的,对于太多层次的嵌套通常可以通过拆分函数的方式来减少嵌套层数。

其他影响可读性的坏味道


影响代码可读性的点还有挺多:

  • 代码行数:过多的行数确实很难理解,而且测试的复杂性也会大大增加。
  • 适当的注释:虽然我们应该尽可能的提升代码的可读性,不过适当的注释还是需要的,特别是比较复杂的逻辑,最好注释一下当时自己为什么这样实现,否则过段时间,可能就不会记得当初自己是怎么想的了。
  • 编码规范:python规范是有相应的编码规范的,如pep8,这是经验的总结,应该多学习学习。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 野生AI架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档