Python 實現 Myapp.exe
1. Github 項目地址
https://github.com/fengoxiao/Myapp/blob/master/Myapp.py
項目要求:
實現一個自動生成小學四則運算題目的命令行程序.
1. 使用 -n 參數控制生成題目的個數
2. 使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的範圍
3.使用 -e,-a參數對給定的題目文件和答案文件,判定答案中的對錯並進行數量統計
4.程序應能支持一萬道題目的生成
設計:
分為3個塊內容,第一個是生成表達式,第二個是寫入文件以及讀取文件,第三個是命令行控制
通過上一次的作業,儲備了知識,使我對字符串的處理能力有所提升,處理帶分數和假分數的相互轉換比較方便,
但是在添加括號的處理以及解析題目文件計算答案還是花了挺多時間的。 其他的基本就按照設計圖的思路按部就班的進行。
主要的函數有:
getSymbol():#獲得符號列表
getNumerical(i,r):#獲得數值列表
calculate(a,b,c):#計算
cf(fraction):#真分數的表達
rcf(fra):#真分數轉化為分數
writeFormula(symbol,numerical,syb):#算術表達式
getFormula(n,r):#生成題目和答案列表
text_save(filename, data):#filename為寫入文件的路徑,data為要寫入數據列表.
answers_read(filename):#解析答案文件
exercises_read(filename):#解析題目文件
checkAnswer(a,e,ra,re):#檢查答案
controlParameter():#命令行控制模塊
if __name__ == ‘__main__‘:#主函數
用戶使用說明:
usage: Myapp.py [-h] [-n N] [-r R] [-e E] [-a A]
optional arguments:
-h, --help show this help message and exit
-n N 題目數量
-r R 題目中數值的範圍
-e E 題目文件
-a A 答案文件
代碼:
所有的功能函數:
def getSymbol():#獲得符號列表 symbol=[] syb=0 i=random.randint(1, 3) for x in range(i): sy=random.choice([‘+‘,‘-‘,‘ב,‘÷‘]) if sy==‘+‘or sy==‘-‘: syb +=10**(i-x-1) else : syb += 2 * (10 ** (i - x - 1)) symbol.append(sy) return symbol,i,syb def getNumerical(i,r):#獲得數值列表 numerical,n,m=[],1,0 if r < 10: n = int(10 / r) if n==1: while m <= i: numerical.append(Fraction(random.randint(1, r), random.randint(1, r))) m+=1 else: while m <= i: nu = Fraction(random.randint(1, r * n), random.randint(1, r * n)) if nu<=r: numerical.append(nu) m += 1 return numerical def calculate(a,b,c):#計算 answer=0 if c==‘+‘: answer=a+b elif c==‘-‘: if a>=b:answer=a-b else:answer=-1 elif c==‘ב: answer=a*b else:answer=a/b return answer def cf(fraction):#真分數的表達 if fraction.numerator%fraction.denominator==0: return ‘%d‘%(fraction.numerator/fraction.denominator) elif fraction.numerator>fraction.denominator: a=int(fraction.numerator/fraction.denominator) b, c = fraction.numerator - a * fraction.denominator, fraction.denominator return ‘%d%s%d%s%d‘ % (a,‘’‘,b,‘/‘,c) else: b, c = fraction.numerator, fraction.denominator return ‘%d%s%d‘ % (b,‘/‘,c) def rcf(fra):#真分數轉化為分數 line = re.sub(r‘[\’\/]‘, ‘ ‘, fra) wo = line.split(‘ ‘) # 空格分割單詞 wo = [int(x) for x in wo] i=len(wo) if i==1: return wo[0] elif i==2: return Fraction(wo[0], wo[1]) else:return Fraction(wo[0]*wo[2]+wo[1], wo[2]) def writeFormula(symbol,numerical,syb):#算術表達式 s=‘‘ if syb>100: if syb == 112 or syb ==212: s = ‘(%s %s %s %s %s) %s %s = ‘ % (cf(numerical[0]), symbol[0], cf(numerical[1]),symbol[1], cf(numerical[2]), symbol[2], cf(numerical[3])) elif syb == 121 or syb ==122: s = ‘(%s %s %s) %s %s %s %s = ‘ % (cf(numerical[0]), symbol[0], cf(numerical[1]),symbol[1], cf(numerical[2]), symbol[2], cf(numerical[3])) else: s = ‘%s %s %s %s %s %s %s = ‘ % (cf(numerical[0]), symbol[0], cf(numerical[1]),symbol[1], cf(numerical[2]), symbol[2], cf(numerical[3])) elif syb>10: if syb == 12: s = ‘(%s %s %s)%s %s = ‘ % (cf(numerical[0]), symbol[0], cf(numerical[1]), symbol[1], cf(numerical[2])) else: s = ‘%s %s %s %s %s = ‘ % (cf(numerical[0]), symbol[0], cf(numerical[1]), symbol[1], cf(numerical[2])) else : s =‘%s %s %s = ‘ % (cf(numerical[0]),symbol[0],cf(numerical[1])) return s def getFormula(n,r):#生成題目和答案列表 Exercises,Answers,Exercises1,Exercises2=[],[],[],[] x=1 while x<n+1: symbol,i,syb=getSymbol() numerical=getNumerical(i,r) answer = numerical[0] legal = True for y in range(i): cal=calculate(answer,numerical[y+1],symbol[y]) if cal>=0:#判斷算式是否合法 answer=cal else: legal=False break if legal:#判斷是否重復題目 try: num=Answers.index(answer)#第一個重復答案的索引 if operator.eq(Exercises1[num],symbol) and operator.eq(Exercises2[num],numerical): pass except ValueError as e:#可以寫入 Answers.append(answer) Exercises1.append(symbol) Exercises2.append(numerical) Exercises.append(‘%d. %s‘%(x,writeFormula(symbol,numerical,syb))) x+=1 else:pass return Exercises,Answers def text_save(filename, data):#filename為寫入文件的路徑,data為要寫入數據列表. file = open(filename,‘a‘) file.seek(0) file.truncate() # 清空文件 for x in data: x=‘%s\n‘%(x) file.write(x) file.close() print(‘%s文件保存成功‘%filename) def answers_read(filename): file = open(filename) read = file.readlines() answers=[] for line in read: line = re.sub(r‘\n‘, ‘‘, line) answers.append(line.split(‘ ‘)[1])#字符串 return answers def exercises_read(filename): file = open(filename) read = file.readlines() answers2= [] for line in read: line = re.sub(r‘[\.\(\)\=\s]+‘, ‘ ‘, line) line = line.strip() # 除去左右的空格 wo = line.split( ) # 空格分割單詞 del wo[0] sy,nu=[],[] for x in range(len(wo)): if x%2: sy.append(wo[x]) else:nu.append(rcf(wo[x])) ans = nu[0] for y in range(len(sy)): ans = calculate(ans, nu[y + 1], sy[y]) answers2.append(ans) return answers2 def checkAnswer(a,e,ra,re): correct,wrong=[],[] for x in range(len(ra)): if operator.eq(ra[x],cf(re[x])): correct.append(x+1) else:wrong.append(x+1) file = open(‘Grade.txt‘, ‘a‘) file.seek(0) file.truncate() # 清空文件 x1=‘Correct:%d%s\n‘%(len(correct),correct) x2=‘Wrong:%d%s‘%(len(wrong),wrong) file.write(x1) file.write(x2) file.close() print(‘題目文件%s與答案文件%s比對成功,結果已存入Grade.txt‘%(e,a)) def controlParameter():#命令行控制模塊 parser = argparse.ArgumentParser() parser.add_argument(‘-n‘, help=‘題目數量‘,type=int) parser.add_argument(‘-r‘, help=‘題目中數值的範圍‘,type=int) parser.add_argument(‘-e‘, help=‘題目文件‘,type=str) parser.add_argument(‘-a‘, help=‘答案文件‘,type=str) return parser.parse_args()
主函數:
if __name__ == ‘__main__‘:#主函數 n=10#設置默認值 args=controlParameter() if args.n: n=args.n if args.r: r=args.r Exercises, Answers=getFormula(n,r) for x in range(n): Answers[x]=‘%d. %s‘%(x+1,cf(Answers[x])) print(‘n,r兩個參數的值為%d,%d:‘%(n,r)) text_save(‘Exercises.txt‘,Exercises) text_save(‘Answers.txt‘,Answers) if args.e and args.a:#‘Answers.txt‘,‘Exercises.txt‘ Answers1=args.a Exercises1=args.e checkAnswer(Answers1,Exercises1,answers_read(Answers1), exercises_read(Exercises1))
測試運行:
普通-n,-r參數測試
一萬道題目測試,經過了稍微久一點的等待:
當r=1時:
-e,-a 測試:
全部功能測試:
以上就是所有功能的測試了。
代碼覆蓋率:
PSP表格
PSP2.1 |
Personal Software Process Stages |
預估耗時(分鐘) |
實際耗時(分鐘) |
Planning |
計劃 |
5 |
5 |
· Estimate |
· 估計這個任務需要多少時間 |
800 |
930 |
Development |
開發 |
480 |
610 |
· Analysis |
· 需求分析 (包括學習新技術) |
60 |
60 |
· Design Spec |
· 生成設計文檔 |
60 |
60 |
· Design Review |
· 設計復審 (和同事審核設計文檔) |
30 |
30 |
· Coding Standard |
· 代碼規範 (為目前的開發制定合適的規範) |
30 |
10 |
· Design |
· 具體設計 |
30 |
60 |
· Coding |
· 具體編碼 |
120 |
480 |
· Code Review |
· 代碼復審 |
30 |
30 |
· Test |
· 測試(自我測試,修改代碼,提交修改) |
120 |
120 |
Reporting |
報告 |
120 |
120 |
· Test Report |
· 測試報告 |
60 |
60 |
· Size Measurement |
· 計算工作量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 事後總結, 並提出過程改進計劃 |
30 |
30 |
合計 |
800 |
975 |
總結:
通過這次作業,思路比較清晰,做的比較快,首先和夥伴交流了思路,然後就開始做。
3個部分剛好用了三天。最後一個命令行因為之前沒有實現,所以花了時間去學習如何使用argparse模塊,挺有收獲的。
雖然寫的過程中有遇到挺多的bug,但是我們都逐一克服了,也總結了經驗的教訓,這樣下次可以寫出更加優質的代碼。
兩個人一起處理工作,兩雙眼睛可以使得工作更加細致,解決問題的能力大大提高,汲取夥伴的好思路,做到1+1>2,事半功倍。
同時這次的課程設計也慢慢的提高我的python理解,只有不斷的練習才能更加熟練。
Python 實現 Myapp.exe