分析一套源代码的代码规范和风格并讨论如何改进优化代码

Posted zhang512

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分析一套源代码的代码规范和风格并讨论如何改进优化代码相关的知识,希望对你有一定的参考价值。

  我的工程实践是有关计算机视觉的,因此我选择了一个计算机视觉的分类任务的代码进行分析。该套代码的主要任务是狗的识别及分类,接下来分析这套代码的结构和规范。

一、源代码目录结构

技术图片

 

   该代码目录结构很清晰明了。主要分为以上几个部分,导入数据集,检测狗狗脸,检测人脸,定义模型,训练模型,结构清晰明了,且根据目录内文件的命名可以清楚得明白该模块所实现的功能,很好得符合了软件设计的要求。

二、命名方面

  由于整套代码的规模较大,这里我们分析命名规范时拿出一部分代码进行分析,比如我们拿出detecdog这一部分进行分析

 1 from keras.applications.resnet50 import ResNet50
 2 
 3 # 定义ResNet50模型
 4 ResNet50_model = ResNet50(weights=imagenet)
 5 
 6 from keras.preprocessing import image
 7 from tqdm import tqdm
 8 
 9 
10 def path_to_tensor(img_path):
11     # 用PIL加载RGB图像为PIL.Image.Image类型
12     img = image.load_img(img_path, target_size=(224, 224))
13     # 将PIL.Image.Image类型转化为格式为(224, 224, 3)的3维张量
14     x = image.img_to_array(img)
15     # 将3维张量转化为格式为(1, 224, 224, 3)的4维张量并返回
16     return np.expand_dims(x, axis=0)
17 
18 
19 def paths_to_tensor(img_paths):
20     list_of_tensors = [path_to_tensor(img_path) for img_path in tqdm(img_paths)]
21     return np.vstack(list_of_tensors)
22 
23 
24 from keras.applications.resnet50 import preprocess_input, decode_predictions
25 
26 
27 def ResNet50_predict_labels(img_path):
28     # 返回img_path路径的图像的预测向量
29     img = preprocess_input(path_to_tensor(img_path))
30     return np.argmax(ResNet50_model.predict(img))
31 
32 
33 def dog_detector(img_path):
34     prediction = ResNet50_predict_labels(img_path)
35     return ((prediction <= 268) & (prediction >= 151))

  首先是文件名的命名,该部分所实现的功能是要检测图片中的狗狗脸是否存在,一般的命名规则是根据文件实现的功能进行命名,那么命名应为类似detection_dog.py之类的名字,本着精简的命名规则,截取名字的主要部分作为文件名可以更简洁地标识出文件,detecdog即标明了该模块的主要功能。

  再来看函数名和变量名。该模块主要包括四个函数,函数名分别为path_to_tensor,paths_to_tensor,ResNet50_predict_labels,dog_detector。同样,这四个函数名采用xx_xx_xx的格式,即单词加下划线的组合,用下划线当做单词之间的分割,清晰明了,更容易让人通过函数名来弄清楚此函数所实现的功能。例如path_to_tensor这个函数名,为路径到张量的过程,通过此模型我们可以明确此函数实现的功能,并且知道这个模型是一个类似TensorFlow的网络结构。变量名如img,x,prediction这几个作为变量的代表。img作为image的简称,用img来代替image实现了表达的简洁,而大家在阅读代码的过程中,看到img又可以知道其代表的含义。x变量可以表示任何东西,但是当我们在程序中使用此变量时,我们一般将其作为临时变量使用。而我们对富有意义的变量命名时,会根据变量所存储的内容进行命名,例如prediction,我们用此变量保存预测值,而不是简单地对其命名为x,y,z等名字。

  再看接口定义。python语言的优势在于python包的完整性,很多内容不需要开发人员再自己进行编写而可以直接导入包进行使用。在导入包的过程中要确定好导入包的名称,例如from keras.applications.resnet50 import ResNet50,该过程确定好包的名称和要导入的功能的名称,这样才不会出差错,接口才可以实现好应有的功能。

三、代码规范

1、文件命名是很规范的,按照文件的内容进行命名;

2、函数的命名也是很规范的,按照xx_xx_xx的格式,将单词进行分割,易读易理解;

3、变量的命名也符合规范,精简明了;

4、代码的结构也符合规范,没有多余的空格,缩进对齐也符合规范。

四、可改进的地方

   一般来说,import的部分需要放在代码段的最上方,并且和代码正文用空格分开,这样最符合规范,也方便他人阅读代码。但是此作者在同一个py文件下防止了两段import,开头一段,代码中间一段,虽然并没有语法错误,但是会对代码的阅读者造成不友好的体验。

  还有就是对于变量的命名方面也有一个容易引起误解的地方,在机器学习中,有时用x来表示训练数据集的特征,有时又用来作为中间的临时变量,如果代码编写者不对此进行说明的话,代码的阅读者同样容易引起误解。因此可以进行一些修改,如将特征用x_features来表示,而中间变量用x_temp来表示。

五、同类语言的要求

1、所有的 Python 脚本文件都应在文件头标上;

2、Python 依赖缩进来确定代码块的层次,行首空白符主要有两种:tab 和 空格,但严禁两者混用。如果使用 tab 缩进,设定tab 为 4 个空格;

3、空格在 Python 代码中是有意义的,因为 Python 的语法依赖于缩进,在行首的空格称为前导空格。非前导空格在 Python 代码中没有意义,但适当地加入非前导空格可以增进代码的可读性;

4、适当的空行有利于增加代码的可读性,加空行可以参考如下几个准则:

  1)在类、函数的定义间增加空格;

  2)在import不同种类的模块间增加空格;

  3)在函数的逻辑段落之间增加空格。

5、尽管现在的宽屏显示器已经可以单屏显示超过 256 列字符,但本规范仍然坚持行的最大长度不得超过 80 个字符的标准;

6、常量名所有字母大写,由下划线连接各个单词;

7、变量名全部小写,由下划线连接各个单词,私有类成员使用单一下划线前缀标识,多定义公开成员,少定义私有成员;

8、对类名使用大写字母开头的单词(如CapWords, 即Pascal风格),不使用下划线连接单词

9、模块名全部小写,对于包内使用的模块,可以加一个下划线前缀;

10、命名应当尽量使用全拼写的单词,缩写的情况有如下两种:

  1)常用的缩写,如 XML、ID等,在命名时也应只大写首字母;

  2)命名中含有长单词,对某个单词进行缩写。这时应使用约定成俗的缩写方式,如去除元音、包含辅音的首字符等方式。

11、import 的次序,先 import Python 内置模块,再 import 第三方模块,最后 import 自己开发的项目中的其它模块;这几种模块用空行分隔开来;

12、通常每个语句应该独占一行。不过, 如果测试结果与测试语句在一行放得下, 你也可以将它们放在同一行。如果是if语句, 只有在没有else时才能这样做。特别地,绝不要对 try/except 这样做,因为try和except不能放在同一行。

以上是关于分析一套源代码的代码规范和风格并讨论如何改进优化代码的主要内容,如果未能解决你的问题,请参考以下文章

分析一套源代码的代码规范和风格并讨论如何改进优化代码

分析一套源代码的代码规范和风格并讨论如何改进优化代码

分析一套源代码的代码规范和风格并讨论如何改进优化代码

分析一套源代码的代码规范和风格并讨论如何改进优化代码

分析一套源代码的代码规范和风格并讨论如何改进优化代码

分析一套源代码的代码规范和风格并讨论如何改进优化代码