5. python练习题5-存款、收益率计算
【目录】
文章目录
- 5. python练习题5-存款、收益率计算
- 1. 目标任务
- 2. 解题思路
- 3. 知识回顾
- 3.1 Python赋值运算符
- 3.2 列表的append函数
- 3.3 round()函数—保留小数点位数
- 3.4 `f`格式化字符串
- 3.5 列表求和方法
- 4. 程序代码
- 4.1 使用循环结构实现
- 4.2 使用函数递归调用实现
【正文】
1. 目标任务
假设每月存100元到一个年利率为6%的储蓄账户。
即月利率=0.06/12=0.005。
第一个月后,账户的存款金额为:100*(1+0.005)=100.5
第二个月后,账户的存款金额为:(100+100.5)*(1+0.005)=201.5025
第三个月后,账户的存款金额为:(100+201.5025)*(1+0.005)=303.01001
请编写程序计算:
5个月后,该储蓄账户的存款金额是多少,要求保留5位小数。
计算总体收益相对总体本金的收益率(此收益率值:总收益/总本金),要求以百分数形式显示,保留2位小数。
2. 解题思路
每个月的账户存款金额以及收益率的计算方法题目已经说得很清楚了。
根据题目要求,我们需要设置一些相关的变量:
- total_deposit:账户存款总额 初始化为0
- wage:每个月打进去的金额=100
- monthly_rate:月利率=0.005
- month_num:总月份数量=5
- rate:收益率
总共求5个月后的数据,而每个月的计算模式都是一样的,因此必然需要一个循环迭代的过程。
最后的收益率计算,总体本金很简单,就是5个月打入的资金总额,也即100*5=500元。
而总体收益为每个月利息的总和,每一轮迭代,能求得每个月的利息。
由于每个月的利息是变动的
,因此,我们还需要提供一个变量来存储每个月的月利息数据
。
这个变量可以设置为一个浮点数
,在每轮迭代中自加该月利息;
也可以设置为一个列表
,在每轮迭代中把该月利息追加进去,最后把列表求和,即:
- income:每个月累计利息 初始化为0; 或:
income_list:存放每个月利息的列表 初始化为空列表[ ]
由于每个月的计算模式都是一样的,因此,我们可以使用循环结构(for循环或while循环),或者函数递归调用的方式来实现这个循环迭代的过程。
在使用函数递归调用方式情况下,还需要预先设置正在迭代第几次的变量i,即:
i
:正在迭代第几次 初始化为0
3. 知识回顾
3.1 Python赋值运算符
上图列出了python所有赋值运算符及其实例,
本例中我们将用到其中的加法赋值运算符:+=,
包括存款金额的自加、月份的自加,以及月利息的自加。
【代码示例】
sum = 0
sum = sum + 2
print(sum)
【终端输出】
2
【+=代码示例】
sum = 0
sum += 2
print(sum)
【终端输出】
2
sum = sum + 2
等同于 sum +=2
赋值运算符能使代码更简洁。
写法就是省略一个sum,并把赋值运算符(加减乘除等)移动等号的左边。
3.2 列表的append函数
列表的append( )函数的作用是向列表的末尾添加元素。
【语法】
列表名.append(要增加的元素)
【代码示例】
# 向列表的末尾添加元素
# 创建列表 name_list
name_list = ['张三', '李四']
# 用 append() 给列表 name_list 添加一个元素 '王五'
# 列表名.append(要增加的元素)
name_list.append('王五')
# 输出 name_list 列表
print(name_list)
【终端输出】
['张三', '李四', '王五']
3.3 round()函数—保留小数点位数
round函数用于设置保留小数点位数,并返回相应的四舍五入的值。
【语法】
round(要格式化的数,保留的小数位数)
保留的小数位数是可选参数,如果没有设置,则四舍五入取值,返回的是整数。
【代码示例】
# 保留3位小数
print(round(3.1415926, 3))
【终端输出】
3.142
3.4 f
格式化字符串
【代码示例】
# f格式化字符串
name = "安迪"
city = "云南"
school = "复旦大学"
print(f"大家好,我叫{name},来自{city},毕业于{school}!")
【终端输出】
大家好,我叫安迪,来自云南,毕业于复旦大学!
【编写思路】
-
我们要输出的内容是:大家好,我叫安迪,来自云南,毕业于复旦大学!
-
把要格式化的内容用英文大括号加变量名{变量名}替换:
安迪替换为大括号加变量名{name}。
云南替换为大括号加变量名{city}。
复旦大学替换为大括号加变量名{school}。
格式化模板为:“大家好,我叫{name},来自{city},毕业于{school}!”
-
添加格式化符号f。
53.Python的f格式化字符串
3.5 列表求和方法
【使用sum()函数】
list1 = [1, 2, 3, 4, 5]
sum_result = sum(list1)
print(sum_result) # 输出:15
【终端输出】
15
【使用循环遍历列表并累加】
list2 = [1, 2, 3, 4, 5]
sum_result = 0
for num in list2:
sum_result += num
print(sum_result) # 输出:15
【终端输出】
15
4. 程序代码
4.1 使用循环结构实现
【代码示例】
# 初始化账户存款金额变量为0
total_deposit=0
# 设置每月打入金额变量为100
wage=100
# 设置每月利率为0.005
monthly_rate=0.005
# 设置总月份数为5
month_num=5
# 初始化利息总数为0
income=0
# 设置for循环,循环次数为总月份数
for i in range(month_num):
# 存款金额在现有总数上加上每月打入金额
total_deposit += wage
# 计算本月利息
monthly_income=total_deposit*monthly_rate
# 利息总数加上本月利息
income+=monthly_income
# 存款金额再加上本月利息
total_deposit+=monthly_income
# 计算最后的总收益率,以百分数形式显示,保留2位小数
rate=f'{round(income/(5*wage)*100,2)}%'
# 打印最后的存款金额
print(f'{month_num}个月后账户的存款金额:{round(total_deposit,5)}元')
# 打印收益率
print(f'收益率:{rate}')
【终端输出】
5个月后账户的存款金额:507.55019元
收益率:1.51%
【解析】
这里采用一个浮点数变量income来存放利息总数,相应的在循环体中就需要将其自加赋值。
用保留2位小数的百分数形式显示收益率时,需要在计算得到的收益率基础上乘以100,
再使用round()函数将其保留2位小数,最后拼接上一个%
字符。
我们也可以使用列表来存放每月利息的:
【代码示例】
# 初始化账户存款金额变量为0
total_deposit=0
# 设置每月打入金额变量为100
wage=100
# 设置每月利率为0.005
monthly_rate=0.005
# 设置总月份数为5
month_num=5
# 初始化每月利息存放列表为空[]
income_list=[]
# 设置for循环,循环次数为总月份数
for i in range(month_num):
# 存款金额在现有总数上加上每月打入金额
total_deposit += wage
# 计算本月利息
monthly_income=total_deposit*monthly_rate
# 把本月利息追加进存放月利息的列表income_list
income_list.append(monthly_income)
# 存款金额再加上本月利息
total_deposit+=monthly_income
# 计算最后的总收益率,以百分数形式显示,保留2位小数
rate=f'{round(sum(income_list)/(5*wage)*100, 2)}%'
# 打印最后的存款金额
print(f'{month_num}个月后账户的存款金额:{round(total_deposit,5)}元')
# 打印收益率
print(f'收益率:{rate}')
【终端输出】
5个月后账户的存款金额:507.55019元
收益率:1.51%
5个月后账户的存款金额:507.55019元
收益率:1.51%
【解析】
这里采用一个列表income_list来存放每月利息,
相应的在循环体中需要对其使用append()方法把该月利息追加进列表,
最后在计算收益率时还需要使用sum()函数对列表元素求和得到利息总数。
4.2 使用函数递归调用实现
每月的数据计算都遵循相似的模式,因此,可以考虑使用函数递归调用的方式来解决问题。
递归函数知识可参考如下链接:
58.Python的递归函数
在使用函数递归调用方法时,需要注意以下几点:
-
递归函数体中的代码需要满足程序逐层级深入的循环往复调用要求,能解决每一层级的问题需求。
-
递归函数体中提供往下级继续调用的,必须是该递归函数本身。
-
递归函数的参数设置和传递的合理准确是递归调用成功的关键。
-
递归函数体中必须设置停止、退出函数调用的正确且有效的条件,否则很可能导致无限调用使程序崩溃的情况。
-
初始调用时若需要获取函数的最终返回值,则必须保证每一层级都能准确返回数据给上一层调用。
【代码示例】
# 初始化账户存款金额变量为0
total_deposit=0
# 设置每月打入金额变量为100
wage=100
# 设置每月利率为0.005
monthly_rate=0.005
# 设置总月份数为5
month_num=5
# 初始化每月利息存放列表为空[]
income_list=[]
# 设置正在迭代第几次,初始化为0
i = 0
# 设置递归函数,参数为迭代次数
def caculate(i):
# 当在函数内部用自加方式修改全局变量时,需要用gloabal进行声明
global total_deposit
# 当i达到设定的总月份数时,终止函数调用
if i==month_num:
# 必须返回
return
# 存款金额在现有总数上加上每月打入金额
total_deposit += wage
# 计算本月利息
monthly_income=total_deposit*monthly_rate
# 把本月利息追加进存放月利息的列表income_list
income_list.append(monthly_income)
# 存款金额再加上本月利息
total_deposit+=monthly_income
# 迭代次数加1
i+=1
# 进行下一轮函数调用,把更新的迭代次数传入
caculate(i)
# 调用递归函数
caculate(i)
# 计算最后的总收益率,以百分数形式显示,保留2位小数
rate=f'{round(sum(income_list)/(5*wage)*100,2)}%'
# 打印最后的存款金额
print(f'{month_num}个月后账户的存款金额:{round(total_deposit,5)}元')
# 打印收益率
print(f'收益率:{rate}')
【终端输出】
5个月后账户的存款金额:507.55019元
收益率:1.51%
【解析】
这里我们创建了一个进行每月数据计算的递归函数caculate,参数为每轮迭代的次数。
存款金额total_deposit是一个浮点数据类型的全局变量,
因此在函数中修改其值时,需要先在函数中使用global语句进行声明。
注意,尽管存放月利息的列表income_list同样也是全局变量,也在函数中修改了数据,
但由于作为可变数据类型的列表,其append()方法是直接在原列表追加元素而没有新建列表,
income_list变量的内存地址并没有发生变化,因此不需要做global语句的声明。
另外,由于一开始的i值只是作为参数把值传入递归函数,
而函数中的i则是函数的局部变量,在递归调用之间进行传递,
并非作为全局变量的一开始的i变量,自然也无需global语句声明。
递归函数体中提供了终止函数调用的判断条件if i==month_num
,满足该条件时return返回,
这样将能有效的终止函数调用,避免出现无限调用使程序崩溃的情况。
我们也可以采用不设置total_deposit为全局变量,而把它作为参数传递给递归函数,
这样将能避免使用global语句声明:
【代码示例】
# 初始化账户存款金额变量为0
total_deposit=0
# 设置每月打入金额变量为100
wage=100
# 设置每月利率为0.005
monthly_rate=0.005
# 设置总月份数为5
month_num=5
# 初始化每月利息存放列表为空[]
income_list=[]
# 设置正在迭代第几次,初始化为0
i=0
# 设置递归函数,参数为迭代次数和存款金额
def caculate(i,total_deposit_):
# 当i达到设定的总月份数时,终止函数调用
if i==month_num:
# 计算最后的总收益率,以百分数形式显示,保留2位小数
rate = f'{round(sum(income_list) / (5 * wage) * 100, 2)}%'
# 打印最后的存款金额
print(f'{month_num}个月后账户的存款金额:{round(total_deposit_, 5)}元')
# 打印收益率
print(f'收益率:{rate}')
# 必须返回
return
# 存款金额在现有总数上加上每月打入金额
total_deposit_ += wage
# 计算本月利息
monthly_income=total_deposit_*monthly_rate
# 把本月利息追加进存放月利息的列表income_list
income_list.append(monthly_income)
# 存款金额再加上本月利息
total_deposit_+=monthly_income
# 迭代次数加1
i+=1
# 进行下一轮函数调用,把更新的迭代次数和当前存款金额传入
caculate(i,total_deposit_)
# 调用递归函数
caculate(i,total_deposit)
【终端输出】
5个月后账户的存款金额:507.55019元
收益率:1.51%
【解析】
可以看到,我们把最后打印输出的语句调整到函数体之中当满足终止调用条件的时候来执行,
同时函数中的total_deposit替换成了total_deposit_(在最后加了一个下划线字符),
改名并不是必需的,只是为了更清晰的与total_deposit变量来做区分,
total_deposit始终都是作为一个全局变量的存在,只不过在最初始调用时将其值传入递归函数而已。
而total_deposit_作为函数的参数,在函数之间的递归调用过程中始终是函数的一个局部变量,
其值的变化并不会影响total_deposit全局变量的值。
那么假如我们仍然把打印输出存款金额的语句放到程序末尾的话,将打印出total_deposit一直固定不变的初始值0。
有同学可能会问,如果一定要在最后打印输出呢?
实际上这个问题的本质,就是在最开始调用递归函数时需要获取调用最终返回的数据,
那怎么实现呢?我们可以看看应该如何修改上面的代码:
【代码示例】
# 初始化账户存款金额变量为0
total_deposit=0
# 设置每月打入金额变量为100
wage=100
# 设置每月利率为0.005
monthly_rate=0.005
# 设置总月份数为5
month_num=5
# 初始化每月利息存放列表为空[]
income_list=[]
# 设置正在迭代第几次,初始化为0
i=0
# 设置递归函数,参数为迭代次数和存款金额
def caculate(i,total_deposit_):
# 当i达到设定的总月份数时,终止函数调用
if i==month_num:
# 同时必须返回此时的迭代次数和存款金额的值
return i,total_deposit_
# 存款金额在现有总数上加上每月打入金额
total_deposit_ += wage
# 计算本月利息
monthly_income=total_deposit_*monthly_rate
# 把本月利息追加进存放月利息的列表income_list
income_list.append(monthly_income)
# 存款金额再加上本月利息
total_deposit_+=monthly_income
# 迭代次数加1
i+=1
# 进行下一轮函数调用,把更新的迭代次数和当前存款金额传入
# 同时把下一轮函数返回的数据返回给上一层调用
return caculate(i,total_deposit_)
# 调用递归函数,并用i,total_deposit两个变量来接收调用最终返回的数据
i,total_deposit=caculate(i,total_deposit)
# 计算最后的总收益率,以百分数形式显示,保留2位小数
rate = f'{round(sum(income_list) / (5 * wage) * 100, 2)}%'
# 打印最后的存款金额
print(f'{month_num}个月后账户的存款金额:{round(total_deposit, 5)}元')
# 打印收益率
print(f'收益率:{rate}')
【终端输出】
5个月后账户的存款金额:507.55019元
收益率:1.51%
【解析】
我们在前面说明函数递归调用所需要注意的几点,其中最后一点就是:
- 初始调用时若需要获取函数的最终返回值,则必须保证每一层级都能准确返回数据给上一层调用。
在上一个例子当中,当满足终止调用的条件时,我们只是做了简单的return,
这样只是返回到上层调用,只起到了终止继续调用的作用,而并没有把执行结果数据进行返回。
在这个例子中,我们除了终止调用之外,还向上层调用返回了调用结束时我们所需要的数据,
另外,每轮的调用也都需要往上层返回结果数据,因此,进行下一轮调用的语句需要在前面加上return进行返回。
就像剥洋葱一样一层层剥开,又一层层合上。
到了最后,我们必须要用两个变量来接收调用最终返回的两个数据,才能在函数外部的代码末尾正确打印输出。
这是正确使用递归函数所特别要注意的地方!