有关模块化编程的资料
看到Clarmy写的模块化编程的文章(http://www.clarmy.net/2018/09/09/briefly-discuss-pythons-modular-programming/),很受启发。文中提到作者写python的三个阶段:(1)所有代码都堆叠在一起;(2)一个project创建一个文件,适当使用函数,但某些常用函数要从别的文件复制粘贴;(3)将常用函数封装在一个tools.py文件里,之后import进来,缺点是这个文件会越来越大。如果熟练使用模块化编程,能大大提高函数复用率,代码也会更简洁清晰。
和做编程工作的朋友讨论,又了解了“高内聚、低耦合”的概念。先用伪代码分割好流程,再一个个写功能的function。这样代码的复用性会提高,整体更清爽。另外要养成好的命名习惯、精炼地加注释等等。科研中常用的代码分割方式就是【读文件】【分析处理数据】和【输出】,如果要修改分析方法的话,改动其中第二部分的函数就好。
有关高内聚低耦合High cohesion & Low coupling基本知识的博客:https://blog.csdn.net/fangkang7/article/details/82684819
规范写法范例
这里是朋友发给我的一个优秀规范写法示例:https://github.com/leekeiling/Cluster/blob/master/Kmeans.py
函数封装练习
正好今天一个朋友找我写一个简单的小程序,就以此为契机,练习一下函数封装。
问题描述
数据存在四个文件夹里,每个文件夹下有100~200个数据文件, 后缀名为.xl
。
原始数据是逗号分割的文本文件,共三列,有标题行:
对每个文件夹里的所有文件,需要只取中间的若干行:
NSBA2ppm:取180行至3060行
NSBA20ppm:取190行至1130行
NSBAcontrolbottom:取190至1600行
NSBAcontroltoplie:取180至1200行
求出Se/C
, 并将每个文件夹下的结果输出到一个xlsx文档即可。
代码
修改前
最开始没有打草稿,写成了这个样子:
import os
import pandas as pd
import numpy as np
paths = [r'./NSBA2ppm',
r'./NSBA20ppm',
r'./NSBAcontrolbottom',
r'./NSBAcontroltoplie']
bounds = [[180, 3060], [190, 1130], [190, 1600], [180, 1200]]
outfiles = ['NSBA2ppm_ratio.xlsx',
'NSBA20ppm_ratio.xlsx',
'NSBAcontrolbottom_ratio.xlsx',
'NSBAcontroltoplie_ratio.xlsx']
for ipath in range(len(path)):
files = os.listdir(paths[ipath]) # sort according to numbers
files.sort(key=lambda x: int(x[:-3]))
ratio = pd.DataFrame(np.zeros((bounds[ipath][1]-bounds[ipath][0]+1, len(files))))
for ifile in range(len(files)):
data = pd.read_csv(paths[ipath]+'/'+files[ifile], header=None, names=['time', 'C', 'Se'], skiprows=2)
data_trimmed = data[bounds[ipath][0]-1:bounds[ipath][1]]
ratio.loc[:, ifile] = data_trimmed['Se'].values/data_trimmed['C'].values
ratio.to_excel(outfiles[ipath], header=False, index=False)
简单是挺简单的,但是缺点不少。循环都只是用数字实现的,代码里有很多的循环变量,不易读。整体复用性也不高,难以修改。后续如果还要进行相同的数据处理就很麻烦。
修改后
参考上面的范例修改之后:
import os
import pandas as pd
import numpy as np
# 这部分是全局变量
paths = [r'./NSBA2ppm',
r'./NSBA20ppm',
r'./NSBAcontrolbottom',
r'./NSBAcontroltoplie']
bounds = [[180, 3060], [190, 1130], [190, 1600], [180, 1200]]
outfiles = ['NSBA2ppm_ratio.xlsx',
'NSBA20ppm_ratio.xlsx',
'NSBAcontrolbottom_ratio.xlsx',
'NSBAcontroltoplie_ratio.xlsx']
def get_files(path):
'''
get all filenames under path
sort according to numbers
'''
files = os.listdir(path)
files.sort(key=lambda x: int(x[:-3])) # ignore ".xl"
return files
def read_data(path, file):
'''
read data from path/file
'''
data = pd.read_csv(path+'/'+file, header=None, names=['time', 'C', 'Se'], skiprows=2)
return data
def cal_ratio(data, bound):
'''
trim data according to bound, and calculate ratio of Se to C
'''
data_trimmed = data[bound[0]-1:bound[1]]
ratio = data_trimmed['Se'].values/data_trimmed['C'].values
return ratio
def print_ratio(ratio, outfile):
'''print results'''
ratio.to_excel(outfile, header=False, index=False)
return()
def main():
for path, bound, outfile in zip(paths, bounds, outfiles):
files = get_files(path)
ratio = pd.DataFrame(np.zeros((bound[1]-bound[0]+1, len(files))), columns=files)
for file in files:
data = read_data(path, file)
ratio.loc[:, file] = cal_ratio(data, bound)
print_ratio(ratio, outfile)
if __name__ == '__main__':
main()
输出的文档:
虽然变长了很多,但各个模块功能一目了然。深刻地感受到模块化编程的优势~