项目介绍及gitcode地址
本次作业实现的功能有 全部的基础功能和附加功能
前端修改利率表 和 科学计算
以及扩展功能: 鼠标停浮按钮,动态网页背景,等等
这个作业属于哪个课程 | < 2301-计算机学院-软件工程> | ||
---|---|---|---|
这个作业要求在哪里 | < 软工实践第二次作业> | ||
这个作业的目标 | < 实现一个科学计算器具备的基本功能,并且UI设计较美观 > | ||
gitcode地址 | 102101436郑择杭 / calculator · GitCode |
PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 40 |
• Estimate | • 估计这个任务需要多少时间 | 25 | 20 |
Development | 开发 | 1150 | 1200 |
• Analysis | • 需求分析 (包括学习新技术) | 120 | 200 |
• Design Spec | • 生成设计文档 | 65 | 35 |
• Design Review | • 设计复审 | 25 | 25 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 35 | 35 |
• Design | • 具体设计 | 65 | 35 |
• Coding | • 具体编码 | 610 | 720 |
• Code Review | • Code Review | 65 | 65 |
• Test | • 测试(自我测试,修改代码,提交修改) | 200 | 150 |
Reporting | 报告 | 190 | 195 |
• Test Report | • 测试报告 | 125 | 65 |
• Size Measurement | • 计算工作量 | 15 | 15 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 55 | 50 |
合计 | 1370 | 1435 |
项目展示
-- 科学计算器
1. 初始界面
有动态背景和浮动按钮
2. 四则运算、取余以及清零AC 和 回退DEL
展示最基本的四则运算和取余功能,以及计算机常见的 AC 和 DEL 功能
3. 错误提示 Error
当用户输入不当,在后台计算错误时会返回Error
4. 读取历史记录Ans
有时用户需要退回之前的计算,需要读取历史记录
5. 科学计算
在后台用python的math库实现了科学计算
--利率计算器
1. 初始界面
点击左上方按钮可以切换为 存款 / 贷款 两种计算方式
2. 计算
根据选中的 贷款 / 存款,在后台进行相应的计算
3. 利率表修改
可以点击右下角的修改按钮,对后台数据库进行修改。修改后会有弹窗提示。
pycharm数据库可视化
数据库使用的是mysql,在mysql 中用SQL语句创建完数据库和表后,用django相应代码可以进行数据库操作同步,在pycharm中可以进行数据库可视化
记录计算器的计算式子,答案和计算精确日期的表cal_record
存款利率表 deposit
贷款利率表 loan
代码展示
前端代码
templates文件下保存着所有html文件,static文件夹下保存着css,js文件
计算器
下面是计算器的代码,其中css,js,以及其他视频,图片资源在static文件夹下
--html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="static/modify.css">
</head>
<body>
<video autoplay muted loop class="bg_fixed">
<source src="static\video\peaceful.mp4" type="video/mp4" />
</video>
<form action="calculate" class="console">
<div class="screen">
<div class="minor"></div>
<div class="main"></div>
</div>
<table class="science">
<tr>
<td>
<div>sin</div>
</td>
<td>
<div>cos</div>
</td>
</tr>
<tr>
<td>
<div>tan</div>
</td>
<td>
<div>Sqrt</div>
</td>
</tr>
<tr>
<td>
<div>Exp</div>
</td>
<td>
<div>ln</div>
</td>
</tr>
<tr>
<td>
<div>!</div>
</td>
<td>
<div>^</div>
</td>
</tr>
<tr>
<td>
<div>π</div>
</td>
<td>
<div>e</div>
</td>
</tr>
</table>
<table class="base">
<tr>
<td>
<div>(</div>
</td>
<td>
<div>)</div>
</td>
<td>
<div>%</div>
</td>
<td>
<div>+</div>
</td>
<td>
<div>AC</div>
</td>
</tr>
<tr>
<td>
<div>7</div>
</td>
<td>
<div>8</div>
</td>
<td>
<div>9</div>
</td>
<td>
<div>-</div>
</td>
<td>
<div>DEL</div>
</td>
</tr>
<tr>
<td>
<div>4</div>
</td>
<td>
<div>5</div>
</td>
<td>
<div>6</div>
</td>
<td>
<div>*</div>
</td>
<td rowspan="2">
<div>ANS</div>
</td>
</tr>
<tr>
<td>
<div>1</div>
</td>
<td>
<div>2</div>
</td>
<td>
<div>3</div>
</td>
<td>
<div>/</div>
</td>
</tr>
<tr>
<td>
<div>00</div>
</td>
<td>
<div>0</div>
</td>
<td>
<div>.</div>
</td>
<td colspan="2">
<div>=</div>
</td>
</tr>
</table>
</form>
</body>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="static/control.js"></script>
<!--<script src="E:\IT_way\Python_home\django\web\static\jquery.js"></script>-->
</html>
--css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
text-align: center;
border-radius: 20px;
}
.console {
/* pos */
width: 635px;
height: 530px;
margin: 50px auto;
padding: 20px;
/* att */
border-radius: 5%;
background-color: rgba(46, 44, 44, .8);
/* txt */
}
.screen {
/* pos */
margin-bottom: 20px;
/* att */
border-radius: 10px;
height: 100px;
background-color: rgba(153, 208, 219, 0.7);
/* txt */
}
.screen .minor,
.screen .main {
text-align: right;
}
.screen .minor {
height: 40px;
font-size: 20px;
font-weight: 400;
line-height: 40px;
overflow: hidden;
}
.screen .main {
height: 60px;
font-size: 40px;
font-weight: 600;
line-height: 60px;
overflow: hidden;
}
.science {
/* pos */
float: left;
/* att */
border-radius: 20px 0 0 20px;
height: 360px;
width: 170px;
background-color: rgba(170, 174, 178, .7);
/* background: transparent url(image.jpg) repeat-y fixed top; */
/* background: url(imgs/stars2.png) no-repeat fixed; */
/* txt */
}
.base {
/* pos */
float: left;
/* att */
border-radius: 0 20px 20px 0;
height: 360px;
width: 425px;
background-color: rgba(205, 210, 216, .7);
/* background: url(imgs/stars2.png) no-repeat fixed; */
/* txt */
}
.base td div,
.science td div {
/* pos */
margin: 6px;
height: 60px;
width: 70px;
/* att */
/* display: inline-block; */
background-color: rgba(255, 255, 255, .5);
/* 背景色 */
box-shadow: 6rpx 6rpx 12px 6rpx rgba(0, 0, 0, .8);
/* 高斯滤镜 */
/* txt */
text-align: center;
line-height: 60px;
font-size: 28px;
font-weight: 600;
}
.base td div:hover,
.science td div:hover {
box-shadow: 0px 0px 10px 3px rgba(0, 0, 0, .3);
transition: all 0.3s;
cursor: pointer;
}
.base td div:active,
.science td div:active {
background-color: rgb(119, 114, 114);
transition: none;
}
.base tr:nth-child(3) td:nth-child(5) div {
height: 130px;
line-height: 130px;
}
.base tr:nth-child(5) td:nth-child(4) div {
width: 150px;
}
.bg_fixed {
position: fixed;
top: 50%;
left: 50%;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
transform: translateX(-50%) translateY(-50%);
transition: 1s opacity;
}
--js
///
let addEvent = function(arr, output) {
arr.forEach((ele, index, cop) => {
ele.addEventListener('click', () => {
if (specify.includes(ele.innerHTML)) {
switch (ele.innerHTML) {
case 'AC':
output.children[0].innerHTML = '';
output.children[1].innerHTML = '';
break;
case 'DEL':
if (output.children[1].innerHTML != '') {
output.children[1].innerHTML = output.children[1].innerHTML.slice(0, -1)
}
break;
case 'ANS':
console.log('ANS')
$.ajax({
url: '/record',
type: 'get',
// data: {
// formula: output.children[1].innerHTML
// },
success: (response) => {
console.log(response.data);
output.children[0].innerHTML = response.data[0] + '='
output.children[1].innerHTML = response.data[1]
},
error: (response) => {
output.children[1].innerHTML = 'ERROR'
}
})
break;
case '=':
$.ajax({
url: '/calculate',
type: 'get',
data: {
formula: output.children[1].innerHTML
},
success: (response) => {
console.log(response);
output.children[0].innerHTML = output.children[1].innerHTML + '='
ans = response.ans
if (ans.length > 24) {
ans = 'The Answer is Too Large'
}
output.children[1].innerHTML = ans
},
error: (response) => {
output.children[1].innerHTML = 'ERROR'
}
})
break;
}
return;
}
output.children[1].innerHTML += ele.innerHTML;
if (scienceOpes.includes(ele.innerHTML))
output.children[1].innerHTML += '(';
})
});
}
let btns = []
let specify = ['AC', 'DEL', '=', 'ANS']
let scienceOpes = ['sin', 'cos', 'tan', 'Sqrt', 'Exp', 'ln']
let btn_sci = document.querySelectorAll('.science div')
let btn_base = document.querySelectorAll('.base div')
let screen = document.querySelector('.screen')
screen.children[1].innerHTML = 'Sqrt(5)'
addEvent(btn_sci, screen)
addEvent(btn_base, screen)
接下去是利率计算器的代码
--html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="static\interest.css">
</head>
<body>
<video autoplay muted loop class="bg_fixed">
<source src="static\video\peaceful.mp4" type="video/mp4" />
</video>
<div class="cover bg_fixed"></div>
<div class="main-body">
<form class="mainBlock">
<div class="label">存款</div>
<div class="labelHidden">贷款</div>
<div class="title">利率计算器</div>
<div class="money"><input type="number" name="money" id="money" placeholder="金额"></div>
<!--金额-->
<div class="time"><input type="number" name="time" id="time" placeholder="时长"></div>
<!--时长-->
<div class="interest"></div>
<div class="btns">
<div class="submit">提交</div>
<div class="modify">查看 / 修改利率表</div>
<div class="confirm">确认修改</div>
<div class="cancel">取消修改</div>
</div>
<table class="loan">
<tbody>
</tbody>
</table>
<table class="deposit">
<tbody>
</tbody>
</table>
<!-- 利率 -->
</form>
</div>
</body>
<script src="static\interest.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</html>
--css
* {
outline: none;
/* box-sizing: border-box; */
}
input,
.submit,
.interest,
.modify,
.confirm,
.cancel {
outline: 0;
border: 0;
border-radius: 20px;
padding-left: 20px;
box-shadow: 2px 2px 8px #065EAF;
}
.mainBlock {
/* pos */
margin: 80px auto;
padding-top: 10px;
/* att */
width: 400px;
height: 500px; /* 800 */
background-color: rgba(255, 255, 255, 0.8);
position: relative;
/* display: inline-block; */
border-radius: 20px;
border-top-left-radius: 0;
}
.label,
.labelHidden {
/* pos */
position: absolute;
top: -50px;
/* att */
height: 50px;
width: 120px;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 10px 10px 0 0;
/* txt */
font-size: 28px;
line-height: 50px;
text-indent: 25px;
color: #065EAF;
}
.label::after {
position: absolute;
right: 5px;
content: '>';
}
.labelHidden {
/* pos */
position: absolute;
left: 0;
top: 0;
z-index: 2;
/* att */
transition: all, .3s;
border-radius: 0 0 10px 10px;
border-top: 2px dotted #065EAF;
display: none;
height: 50px;
width: 120px;
background-color: whitesmoke;
content: '贷款';
}
.label:hover::after {
/* transform: translate(); */
/*transition: all .1s;*/
transform-origin: 72% 50%;
transform: rotate(90deg);
}
/*
.label::before:hover {
display: inline-block;
} */
.label:active,
.labelHidden:active {
transition: none;
color: whitesmoke;
background-color: #065EAF;
}
.title {
/* pos */
margin: 15px auto;
position: relative;
padding-top: 10px;
/* att */
height: 60px;
width: 100%;
/* background: rgb(198, 197, 197); */
/* txt */
font-size: 30px;
text-align: center;
font-weight: 700;
line-height: 50px;
color: #065EAF;
box-shadow: 0 6px 8px #065EAF;
}
#money,
#time {
/* pos */
margin-left: 80px;
margin-top: 20px;
/* att */
height: 40px;
width: 250px;
/* txt */
font-size: 20px;
font-weight: 400;
line-height: 18px;
}
#money:placeholder-shown,
#time:placeholder-shown {
font-size: 20px;
font-weight: 300;
line-height: 22px;
}
.money,
.time {
position: relative;
display: inline-block;
}
.money:hover,
.time:hover,
.interest:hover,
.submit:hover,
.modify:hover,
.confirm:hover,
.cancel:hover {
transition: all .3s;
transform: scale(1.005);
}
.submit:hover,
.modify:hover,
.confirm:hover,
.cancel:hover {
transform: scale(1.05);
}
.money::before,
.time::before {
/* pos */
position: absolute;
left: 20px;
top: 22px;
/* att */
transition: none;
content: '';
width: 60px;
height: 30px;
/* background-color: aquamarine; */
/* txt */
font-size: 26px;
color: #065EAF;
font-weight: 500;
/* line-height: 30; */
}
.money::before:hover,
.time::before:hover {
transition: none;
border-right: 1px solid #065EAF;
}
.money::before {
content: '金额';
}
.time::before {
content: '时长';
}
.interest {
/* pos */
position: relative;
margin-top: 30px;
margin-left: 75px;
padding-left: 20px;
/* att */
width: 280px;
height: 50px;
background-color: white;
/* txt */
font-weight: 500;
font-size: 28px;
line-height: 50px;
}
.interest::before {
/* pos */
position: absolute;
left: -65px;
top: -2px;
/* att */
content: '利率';
/* txt */
color: #065EAF;
}
.bg_fixed {
position: fixed;
top: 50%;
left: 50%;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
transform: translateX(-50%) translateY(-50%);
transition: 1s opacity;
}
.cover {
background-color: rgba(244, 236, 236, 0.1);
/* min-width: 50%; */
}
.submit,
.modify,
.confirm,
.cancel {
/* pos */
display: inline-block;
/* att */
background-color: #065EAF;
height: 50px;
width: 220px;
/* txt */
padding: 0;
margin-left: 15px;
color: whitesmoke;
font-weight: 700;
font-size: 20px;
text-align: center;
cursor: pointer;
line-height: 50px;
}
.btns {
margin-top: 50px;
margin-bottom: 20px;
}
.submit:active,
.modify:active,
.confirm:active,
.cancel:active {
transition: none;
background-color: whitesmoke;
color: #065EAF;
}
.submit{
width: 130px;
}
.deposit,
.loan {
/* pos */
display: block;
margin: 0 auto;
/* att */
width: 300px;
/* txt */
color: #065EAF;
font-size: 22px;
text-align: left;
}
.deposit input,
.loan input {
width: 100px;
height: 30px;
font-size: 16px;
}
.deposit tr td:first-child,
.loan tr td:first-child {
width: 170px;
}
.deposit tr td,
.loan tr td {
display: inline-block;
height: 45px;
}
.deposit tr:hover div,
.loan tr:hover div,
.deposit tr:hover div,
.loan tr:hover div {
border-bottom: 2px solid #065EAF;
}
.deposit {
display: none;
}
.loan {
display: none;
}
.confirm,
.cancel {
width: 100px;
display: none;
}
--js
// label
let label = document.querySelector('.label');
let labelHidden = document.querySelector('.labelHidden');
labelHidden.style.display = 'none';
label.addEventListener('click', () => {
if (labelHidden.style.display == 'none')
labelHidden.style.display = 'inline-block';
else
labelHidden.style.display = 'none';
})
labelHidden.addEventListener('click', () => {
let innerHtml = label.innerHTML;
label.innerHTML = labelHidden.innerHTML;
labelHidden.innerHTML = innerHtml;
labelHidden.style.display = 'none';
})
labelHidden.addEventListener('mouseout', () => {
labelHidden.style.display = 'none';
})
// change the table
// let current_label = label.innerHTML;
let modify_btn = document.querySelector('.modify');
let deposit = document.querySelector('.deposit');
let loan = document.querySelector('.loan');
let confirm = document.querySelector('.confirm');
let cancel = document.querySelector('.cancel');
let mainBlock = document.querySelector('.mainBlock');
let submit = document.querySelector('.submit');
// ajax
modify_btn.addEventListener('click', () => {
let current_label = label.innerHTML;
let u = '/deposit';
if (current_label === '贷款') u = '/loan';
$.ajax({
url: u,
type: 'get',
// data: {
// contents
// },
success: (response) => {
current_label = label.innerHTML;
modify_btn.style.display = 'none';
confirm.style.display = 'inline-block';
cancel.style.display = 'inline-block';
let change
if (current_label === '存款') {
deposit.style.display = 'block';
loan.style.display = 'none';
change = deposit.children[0];
}
if (current_label === '贷款') {
loan.style.display = 'block';
deposit.style.display = 'none';
change = loan.children[0];
}
let length = String(47*Object.keys(response).length+500) + 'px'
console.log(length)
mainBlock.style.height = length;
/// manage the database
change.innerHTML = ''
for (let key in response){
change.innerHTML += " <tr>\n" +
" <td>\n" +
" <div>"+ key + "</div>\n" +
" </td>\n" +
" <td>\n" +
" <input type=\"number\"value="+response[key] + " >\n" +
" </td>\n" +
" </tr> "
}
},
error: (response) => {
alert('DATABASE ERROR');
}
})
})
let vanish = function (){
deposit.children[0].innerHTML = ''
loan.children[0].innerHTML = ''
deposit.style.display = 'none';
loan.style.display = 'none';
confirm.style.display = 'none';
cancel.style.display = 'none';
modify_btn.style.display = 'inline-block';
mainBlock.style.height = '500px';
}
confirm.addEventListener('click', () => {
let u = '/modify'
let current_label = label.innerHTML;
let change = deposit.children[0]
if (label.innerHTML === '贷款')
change = loan.children[0]
let data = {}
for(let tr_id =0; tr_id<(change.children.length); tr_id++){
let tr = change.children[tr_id]
let td0 = tr.children[0]
let td1 = tr.children[1]
let key =td0.children[0].innerHTML;
let value =td1.children[0].value;
data[td0.children[0].innerHTML] = td1.children[0].value;
}
console.log(data)
let change_table = 'deposit'
if (current_label === '贷款')
change_table = 'loan'
data['table'] = change_table
$.ajax({
url: u,
type: 'get',
data: data,
success: (response) => {
if(response.flag === 1){
alert('修改成功');
}
else{
alert('MODIFY ERROR');
}
},
error: (response) => {
alert('DATABASE ERROR');
}
})
vanish();
})
cancel.addEventListener('click', vanish)
submit.addEventListener('click', ()=>{
let money = document.querySelector('.money input').value;
let time = document.querySelector('.time input').value;
let u = '/interestCal';
let table_name = 'deposit'
if(label.innerHTML === '贷款')
table_name = 'loan';
$.ajax({
url: u,
type: 'get',
data: {
'money': money,
'time': time,
'table': table_name
},
success: (response) => {
document.querySelector('.interest').innerHTML = response.data
},
error: (response) => {
alert('DATABASE ERROR');
}
})
})
后端代码
接下去是后端代码,数据库的调用以及计算器的逻辑实现都在后端进行
计算器的逻辑代码:利用正则表达式提取前端输入式子,转化成由数字和操作符组成的列表后,利用数字栈和操作符栈进行相应的计算,并对科学计算符,阶层等科学计算进行额外的处理
--计算器的代码逻辑
import math
import re
from math import *
science_opes = ['sin', 'cos', 'tan', 'Sqrt', 'Exp', 'ln']
def factorial(num):
if num <= 0:
return 0
return num if num == 1 else num * factorial(num-1)
def formula_format(formula):
"""
:param formula: str
"""
formula = re.sub(' ', '', formula) # delete spaces
#
# \- : matches the begin; \d+ matches the number;\.? matches '.' for once or none;\d*
formula_list = [i for i in re.split('(-[\d+,π,e]\.?\d*)', formula) if i]
final_formula = [] #
for item in formula_list:
# 算式以横杠开头,则第一个数字为负数,横杠为负号
if len(final_formula) == 0 and re.match('-[\d+,π,e]\.?\d*$', item):
final_formula.append(item)
continue
# 如果当前的算式列表最后一个元素是运算符['+', '-', '*', '/', '(', '%', '^'], 则横杠为减号
if len(final_formula) > 0:
if re.match('[\+\-\*\/\(\%\^]$', final_formula[-1]):
final_formula.append(item)
continue
# 按照运算符分割开
item_split = [i for i in re.split('([\+\-\*\/\(\)\%\^\!])', item) if i]
final_formula += item_split
return final_formula
def is_operator(ele):
"""
:param e: str
:return: bool
"""
opes = ['+', '-', '*', '/', '(', ')', '%', '^', 'sin', 'cos', 'tan', 'Sqrt', 'Exp', 'ln', '!']
return True if ele in opes else False
# 比较连续两个运算符来判断是压栈还是弹栈
def decision(tail_op, now_op):
"""
:param tail_op: last element of stack_op
:param now_op: current operation from formula
:return: 1 means pop, 0 means pop last '(' in the stack_op, -1 means push
"""
# 定义4种运算符级别
rate1 = ['+', '-']
rate2 = ['*', '/', '%']
rate3 = ['sin', 'cos', 'tan', 'Sqrt', 'Exp', 'ln', '!', '^']
rate4 = ['(']
rate5 = [')']
if tail_op in rate1:
if now_op in rate2 or now_op in rate3 or now_op in rate4:
return -1 # current operator is at a higher rate, need to push
else:
return 1 # the rate of the two opes are equal, need to calculate
elif tail_op in rate2:
if now_op in rate3 or now_op in rate4:
return -1
else:
return 1
elif tail_op in rate3:
if now_op in rate4:
return -1
else:
return 1
elif tail_op in rate4:
if now_op in rate5:
return 0 # '('遇上')',需要弹出'('并丢掉')',表明该括号内的算式已计算完成并将结果压入数字栈中
else:
return -1 # 只要栈顶元素为'('且当前元素不是')',都应压入栈中
# 传入两个数字,一个运算符,根据运算符不同返回相应结果
def cal(n1, n2, operator):
"""
:param n1: float
:param n2: float
:param operator: + - * / % ^
:return: float
"""
result = 0
if operator == '+':
result = n1 + n2
if operator == '-':
result = n1 - n2
if operator == '*':
result = n1 * n2
if operator == '/':
result = n1 / n2
if operator == '%':
result = n1 % n2
if operator == '^':
result = n1 ** n2
return result
def scienceOpe(op_stack, num_stack):
# science_opes = ['sin', 'cos', 'tan', 'Sqrt', 'Exp', 'ln']
if len(op_stack) == 0 or op_stack[-1] not in science_opes:
return
op = op_stack.pop()
num = num_stack.pop()
if op == 'Sqrt':
num_stack.append(sqrt(num))
elif op == 'sin':
num_stack.append(sin(num))
elif op == 'cos':
num_stack.append(cos(num))
elif op == 'tan':
num_stack.append(tan(num))
elif op == 'Exp':
num_stack.append(exp(num))
elif op == 'ln':
num_stack.append(log(num))
# 负责遍历算式列表中的字符,决定压入数字栈中或压入运算符栈中或弹栈运算
def final_calc(formula_list):
"""
:param formula_list: 算式列表
:return: 计算结果
"""
num_stack = [] # 数字栈
op_stack = [] # 运算符栈
for item in formula_list:
operator = is_operator(item)
# if it's the number
if not operator:
# transfer π and e into a value that could be calculated
if item == 'π':
num_stack.append(pi)
elif item == '-π':
num_stack.append(-pi)
elif item == 'e':
num_stack.append(e)
elif item == '-e':
num_stack.append(-e)
else:
num_stack.append(float(item)) # 字符串转换为浮点数
# if it's the operator
else:
while True:
if item == '!':
num_stack.append(factorial(int(num_stack.pop())))
break
# if length of operator_stack is empty, push it into the stack without other conditions
if len(op_stack) == 0:
op_stack.append(item)
break
# else compare the priority with last operator
tag = decision(op_stack[-1], item)
# if -1, just push it into the stack and break
if tag == -1:
op_stack.append(item)
break
# if 0, pop last '(' and drop current')'
elif tag == 0:
op_stack.pop()
scienceOpe(op_stack, num_stack) # scienceOperations before '('
break
# if 1, we need to pop last operator
# 如果是1,则弹出运算符栈内最后一个元素和数字栈内最后两个元素
elif tag == 1:
if item in science_opes:
op_stack.append(item)
break
op = op_stack.pop()
num2 = num_stack.pop()
num1 = num_stack.pop()
# 将计算结果压入数字栈并接着循环,直到遇到break跳出循环
num_stack.append(cal(num1, num2, op))
# 大循环结束后,数字栈和运算符栈中可能还有元素的情况
while len(op_stack) != 0:
op = op_stack.pop()
num2 = num_stack.pop()
num1 = num_stack.pop() if len(num_stack) > 0 else None
num_stack.append(cal(num1, num2, op))
result = str(num_stack[0])
# 去掉无效的0和小数点,例:1.0转换为1
if result[len(result) - 1] == '0' and result[len(result) - 2] == '.':
result = result[0:-2]
return result
def calculate(formula):
formula_list = formula_format(formula)
return final_calc(formula_list)
--利率计算器的代码逻辑
register_deposit = {
'三个月': lambda x: x == 0.25,
'半年': lambda x: x == 0.5,
'一年': lambda x: x == 1,
'两年': lambda x: x == 2,
'三年': lambda x: x == 3,
'五年': lambda x: x == 5,
}
register_loan = {
'半年以下': lambda x: x < 0.5,
'半年至一年': lambda x: .5 <= x < 1.,
'一至三年': lambda x: 1. <= x < 3.,
'三至五年': lambda x: 3. <= x < 5.,
'五年以上': lambda x: .5 <= x,
}
def interestCalculate(money: float,
time: float,
table_dict: dict,
table_name: str):
register = register_deposit if table_name == 'deposit' else register_loan
for limitation, judge in register.items():
if judge(time): # corresponding limitation
rate = table_dict[limitation]
money *= rate
return money * time
if table_name == 'deposit':
money *= table_dict['活期']
return money * time
心得体会
- 首先就是技术问题了,这次作业实在是发的有点突然,因为之前只有过一些基本的前端知识和python编程知识,制作过静态网页,没学过前后端交互的相关知识
- 然后就是一礼拜速成前后端知识,先学会大致的框架应用,交互代码等基础知识,一点一点去实现每个功能,然后碰到不会的再去借助互联网,以及求助大佬
- 在这次开发过程中狠狠体会到了一个完整的前后端应用是怎么开发出来的,熟悉了开发的流程,包括开发前的整体计划,开发时候进行需求分析,生成设计文档,实现需求的具体编码,以及开发完成后,进行单元测试等
- 在实现过程中,先后学习(复习)了,进行前端界面开发的标准三件套html, css, js, 进行前后端异步交互的ajax,进行后端开发的django框架和 python语言,操纵数据库的mysql技术,以及利用浏览器的开发者模式进行调试和debug
- 感觉还得是ddl哈哈哈哈哈哈,之前做梦都没想到一礼拜能从几乎零基础做出一个完整的前后端应用(虽然不算太复杂),但是该有的前端,后端,交互功能以及数据库 都有了,在这次项目开发中,收获真的非常多啊(头发也掉了非常多