2020软件工程第一次个人编程作业
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2020 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167 |
这个作业的目标 | 制作一个程序完成对GitHub用户行为的统计与分析 |
学号 | 031802207 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
Estimate | 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | ||
Analysis | 需求分析 (包括学习新技术) | 120 | 240 |
Design Spec | 生成设计文档 | 60 | 60 |
Design Review | 设计复审 | 60 | 60 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 480 | 600 |
Code Review | 代码复审 | 60 | 120 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 120 |
Reporting | 报告 | ||
Test Report | 测试报告 | 30 | 30 |
Size Measurement | 计算工作量 | 30 | 30 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 120 | 120 |
合计 | 1200 | 1500 | |
解题思路描述: | |||
第一次个人编程作业就完完全全触及我的知识盲区,现在就是在课业繁重的同时还得学如何使用Git和GitHub、json,重拾不大咋会的Python(我爱数学建模,我爱操作系统,我爱数据库……) | |||
大致思路: | |||
首先从文件夹读入文档,其次对数据进行分析、统计,随后将处理完的数据按要求输出。 | |||
一开始看到示例代码就先扔到pycharm中运行,但是没有得到想要的结果(那是当然的怎么会这么简单呢?) | |||
9月10日更新: | |||
学习GitHub的使用教程,强忍着不去套机翻靠我六级飘过的水平把全英文的教学文档看了一遍。(还是不太懂,先做了再说)将助教的仓库fork到自己的仓库里。继续下一步。 | |||
9月12日更新: | |||
参照廖雪峰老师的Git教程(https://www.liaoxuefeng.com/wiki/896043488029600 ) 以及菜鸟教程(https://www.runoob.com/git/git-tutorial.html ) 学习Git的安装配置和使用。 | |||
有关Git | |||
Git常用有6个命令:git clone、git push、git add、git commit、git checkout、git pull | |||
创建仓库命令 | |||
git init:初始化仓库 | |||
git clone:拷贝一份远程仓库,即下载一个项目 |
提交与修改
git add:添加文件到仓库
git status:查看仓库当前的状态,显示有变更的文件
git diff:比较文件的不同,即暂存区与工作区的差异
git commit:提交暂存区到本地仓库
git reset:回退版本
git rm:删除工作区文件
git mv:移动或重命名工作区文件
提交日志
git log:查看历史提交记录
git blame
远程操作
git remote:远程仓库操作
git fetch:从远程获取代码库
git pull:下载远程代码并合并
git push:上传远程代码并合并
9月15日更新:
果然DDL才是第一生产力,开始研究示例代码(重新捡起好久没写的Python),然而学了一下午还是没大看懂。转去研究了测试文件,发现格式是json格式,在Python中可以直接调用JSON库对json文件进行操作。
有关JSON
JSON是一种轻量级的数据交换格式,易于用户阅读和编写。本次实践中需要用到json.loads和json.dumps两个函数,json.dumps用于将Python对象编码成JSON字符串;而json.loads用于阶码JSON数据,返回Python字段的数据类型。
有关命令行参数解析
看着代码束手无策,后面向班里大佬请教发现需要命令行参数解析进行传参,附上学习网站(https://www.runoob.com/python/python-command-line-arguments.html )
然而用神奇的pycharm就可以直接从RUN中设置parameter插入路径来实现命令行参数解析,即-i path;其中值得注意的是,在插入路径的时候,需要对路径里的反斜杠进行转义,可以通过用正斜杠替换或者在每个反斜杠前再加一个反斜杠来实现转义。(下附截图)
设计实现过程:
代码说明:
添加命令行参数
def argInit(self): self.parser.add_argument('-i', '--init') self.parser.add_argument('-u', '--user') self.parser.add_argument('-r', '--repo') self.parser.add_argument('-e', '--event')
对命令进行解析
def analyse(self): if self.parser.parse_args().init: self.data = Data(self.parser.parse_args().init, 1) return 0 else: if self.data is None: self.data = Data() if self.parser.parse_args().event: if self.parser.parse_args().user: if self.parser.parse_args().repo: res = self.data.getEventsUsersAndRepos( self.parser.parse_args().user, self.parser.parse_args().repo, self.parser.parse_args().event) else: res = self.data.getEventsUsers( self.parser.parse_args().user, self.parser.parse_args().event) elif self.parser.parse_args().repo: res = self.data.getEventsRepos( self.parser.parse_args().reop, self.parser.parse_args().event) else: raise RuntimeError('error: argument -l or -c are required') else: raise RuntimeError('error: argument -e is required') return res
初始化
` def init(self, dict_address: int = None, reload: int = 0):
if reload == 1:
self.__init(dict_address)
if dict_address is None and not os.path.exists('1.json') and not os.path.exists('2.json') and not os.path.exists('3.json'):
raise RuntimeError('error: init failed')
x = open('1.json', 'r', encoding='utf-8').read()
self.__4Events4PerP = json.loads(x)
x = open('2.json', 'r', encoding='utf-8').read()
self.__4Events4PerR = json.loads(x)
x = open('3.json', 'r', encoding='utf-8').read()
self.__4Events4PerPPerR = json.loads(x)
def __init(self, dict_address: str):
self.__4Events4PerP = {}
self.__4Events4PerR = {}
self.__4Events4PerPPerR = {}
for root, dic, files in os.walk(dict_address):
for f in files:
if f[-5:] == '.json':
json_list = []
json_path = f
x = open(dict_address+'\\'+json_path,
'r', encoding='utf-8').read()
str_list = [_x for _x in x.split('\n') if len(_x) > 0]
for i, _str in enumerate(str_list):
try:
json_list.append(json.loads(_str))
except:
pass
records = self.__listOfNestedDict2ListOfDict(json_list)
for i in records:
if not self.__4Events4PerP.get(i['actor__login'], 0):
self.__4Events4PerP.update({i['actor__login']: {}})
self.__4Events4PerPPerR.update({i['actor__login']: {}})
self.__4Events4PerP[i['actor__login']][i['type']
] = self.__4Events4PerP[i['actor__login']].get(i['type'], 0)+1
if not self.__4Events4PerR.get(i['repo__name'], 0):
self.__4Events4PerR.update({i['repo__name']: {}})
self.__4Events4PerR[i['repo__name']][i['type']
] = self.__4Events4PerR[i['repo__name']].get(i['type'], 0)+1
if not self.__4Events4PerPPerR[i['actor__login']].get(i['repo__name'], 0):
self.__4Events4PerPPerR[i['actor__login']].update({i['repo__name']: {}})
self.__4Events4PerPPerR[i['actor__login']][i['repo__name']][i['type']
] = self.__4Events4PerPPerR[i['actor__login']][i['repo__name']].get(i['type'], 0)+1
with open('1.json', 'w', encoding='utf-8') as f:
json.dump(self.__4Events4PerP,f)
with open('2.json', 'w', encoding='utf-8') as f:
json.dump(self.__4Events4PerR,f)
with open('3.json', 'w', encoding='utf-8') as f:
json.dump(self.__4Events4PerPPerR,f)
def __parseDict(self, d: dict, prefix: str):
_d = {}
for k in d.keys():
if str(type(d[k]))[-6:-2] == 'dict':
_d.update(self.__parseDict(d[k], k))
else:
_k = f'{prefix}__{k}' if prefix != '' else k
_d[_k] = d[k]
return _d
def __listOfNestedDict2ListOfDict(self, a: list):
records = []
for d in a:
_d = self.__parseDict(d, '')
records.append(_d)
return records
def getEventsUsers(self, username: str, event: str) -> int:
if not self.__4Events4PerP.get(username,0):
return 0
else:
return self.__4Events4PerP[username].get(event,0)
def getEventsRepos(self, reponame: str, event: str) -> int:
if not self.__4Events4PerR.get(reponame,0):
return 0
else:
return self.__4Events4PerR[reponame].get(event,0)
def getEventsUsersAndRepos(self, username: str, reponame: str, event: str) -> int:
if not self.__4Events4PerP.get(username,0):
return 0
elif not self.__4Events4PerPPerR[username].get(reponame,0):
return 0
else:
return self.__4Events4PerPPerR[username][reponame].get(event,0)`
代码规范连接
https://github.com/Lostsoul-namespace/2020-personal-python/blob/master/codestyle.md
优化思路
python众所周知跑得慢,尤其单线程,跑大量数据就更慢,所以大致的优化思路应该是往多线程的方向优化,但是菜鸡并没有掌握多线程的写法,只能写下大致思路。
性能测试截图
这里的性能测试是通过pycharm里的profile直接生成)
总结
(数学建模老折磨人)
python从入门到入土
几天时间逼着自己学好多看不懂的东西,很多知识不是看看就会,尤其是计算机,
还是得理论结合实际才能出效果。
最后,希望之后的项目中自己能够不这么狼狈吧,不要再拿ddl是第一生产力当借口!!!