![]() |
3.8 上机实践演练
|
又到了实践演练的时候了,主题是制作成绩单统计程序,输入10位学生的姓名以及数学、英语和语文三科的成绩,计算总分、平均分并根据平均分判断属于甲、乙、丙、丁哪一个等级。
这次学生的成绩不使用input()函数一个个输入了,太费时,笔者事先建立了scores.csv文件,文件里包含10位学生的姓名以及数学、英语和语文三科的成绩,3.8.2小节将会介绍如何读取CSV文件。
此次演练的题目要求如下:
(1)读入CSV文件,文件名为scores.csv。
(2)计算总分、平均分以及等级(甲、乙、丙、丁)。
甲:平均80~100分 乙:平均60~79分
丙:平均50~59分 丁:平均50分以下
(3)输出学生姓名、总分、平均分(保留到小数点后1位)和等级。
输入说明
读入scores.csv文件。
输出结果参考图3-15。
流程图如图3-16所示。
图3-15
图3-16
CSV文件是常见的开放数据(Open Data)格式。所谓开放数据,是指可以被自由使用和散布的数据,虽然有些开放数据要求用户标示数据源与所有人,但大部分政府数据的开放平台可以免费获取数据,这些开放数据会以常见的开放格式在网络上公开。不同的应用程序如果想要交换数据,必须借助通用的数据格式,CSV格式就是其中的一种,全名为Comma-Separated Values,字段之间以逗号“,”分隔,与TXT文件一样都是纯文本文件,可以用记事本等文本编辑器来编辑。
CSV格式常用在电子表格以及数据库,比如Excel文件可以将数据导出成CSV格式,也可以导入CSV文件进行编辑。网络上许多开放数据(Open Data)通常也会给用户提供直接下载的CSV格式数据,当大家学会了CSV文件的处理之后,就可以将这些数据用于更多的分析和应用了。
本范例程序使用的scores.csv文件内容如图3-17所示。
图3-17
Python内建csv模块(module),能够非常轻松地处理CSV文件。csv模块是标准库模块,使用前必须先用import指令导入。下面来看csv模块的用法。
csv模块的用法
csv模块既可以读取CSV文件,也可以写入CSV文件,读取之前必须先打开CSV文件,再使用csv.reader方法读取CSV文件里的内容,代码如下:
import csv #载入csv.py with open("scores.csv", encoding="utf-8") as csvfile: #打开文件指定为csvfile reader = csv.reader(csvfile) #返回reader对象 for row in reader: #for循环逐行读取数据 print(row)
上面程序的执行结果如图3-18所示。
图3-18
如果CSV文件与.py文件放在不同的文件夹中,就必须加上文件的完整路径。
open()指令会将CSV文件开启并返回文件对象,范例程序中将文件对象赋值给csvfile变量,默认文件使用unicode编码,如果文件使用不同的编码,就必须使用encoding参数设置编码。本范例程序所使用的CSV文件是无BOM的utf-8格式,所以encoding="utf-8"。
csv.reader()函数会读取CSV文件,转成reader对象再返回给调用者,reader对象是可以迭代(iterator)处理的字符串(string)列表(List)对象。上面的程序中使用reader变量来接收reader对象,再通过for循环逐行读取数据:
reader = csv.reader(csvfile) #返回reader对象 for row in reader: #for循环逐行读取数据放入row变量中
列表对象是Python的容器数据类型(Container Type),它是一串由逗号分隔的值,用中括号“[]”括起来:
['方小花', '87', '100', '98']
上面的列表对象共有4个元素,使用中括号“[]”搭配元素的下标(index,或称为索引)就能存取每一个元素,下标从0开始,从左到右分别是row[0]、row[1]……。例如要获取第4个元素的值,可以如下表示:
name = row[3]
使用with语句打开文件
在读取或写入文件之前,必须先使用open()函数将文件打开;当读取或写入完成时,必须使用close()函数将文件关闭,以确保数据已被正确读出或写入文件。如果在调用close()方法之前发生异常,那么close()方法将不会被调用,举例来说:
f = open("scores.csv") #打开文件 csvfile = f.read() #读取文件内容 1 / 0 #error f.close() #关闭文件
第3行程序语句犯了分母为0的错误,执行到此,程序就会停止执行,所以close()不会被调用,这样可能会有文件损坏或数据遗失的风险。
有两特种方法可以避免这样的问题:一种方法是加上try…except语句捕获错误,另一种方法是使用with语句。Python的with语句配有特殊的方法,文件被打开之后,如果程序发生异常,就会自动调用close()方法,如此一来,就能确保已打开的文件被正确、安全地关闭。
这个范例程序使用的scores.csv文件包含10位学生的姓名及数学、英语和语文三科的成绩,我们需要将三科成绩加总、计算平均分,再以平均分来评比等级。
scores.csv文件第一行是标题,必须略过不处理,所以我们使用一个变量x来记录当前读取的行数,x的初始值为0,x必须大于0,if条件判断表达式才会为真,代码如下:
with open("scores.csv",encoding="utf-8") as csvfile: x = 0 #设置x初始值为0 for row in csv.reader(csvfile): if x > 0: #当x>0时,if判断表达式为真 … x += 1 #相当于x=x+1
编写Python程序的时候不同区块记得缩排,上面的语句共有三个区块,即with…as区块、for循环区块、if区块,x=0的声明必须放在for循环外面,x+=1语句放在for循环内,这样每一次循环x才会累加,如图3-19所示。
图3-19
进入if区块之后要将三科成绩加总,由于csv.reader函数读入的都是字符串(string)格式,因此计算前必须先转换成int格式,再将加总结果赋值给变量scoreTotal:
scoreTotal = int(row[1]) + int(row[2]) + int(row[3])
接着计算平均值,题目要求平均值保留到小数点后1位:
average = round(scoreTotal / 3, 1)
使用平均分来评级,4个等级的分数区间如下。
·甲:平均80~100分。
·乙:平均60~79分。
·丙:平均50~59分。
·丁:平均50分以下。
平均80~100分就评定为“甲”等,80分也在这一区间,因此必须用“>=”(大于等于)关系运算符,如果只用average>80来判断,80分就不会落在这一区间。
平均60~79分就评定为“乙”等,这个判断需要两个条件,average>=60以及average<80,而且两个条件必须都符合,所以必须用and(与)来判断:
average > = 60 and average < 80
由于这两个条件是一个数值区间,因此可以写成下面的表达式,表示average的值必须在60~79以内。
60 <= average < 80
完整if...else语句如下:
if average >= 80 : grade = "甲" elif 60 <= average < 80: grade = "乙" elif 50 <= average < 60: grade = "丙" else: grade = "丁"
最后只要将总分(scoreTotal)、平均分(average)以及等级(grade)用print语句输出就完成了,执行结果如图3-20所示。
图3-20
以下是完整的程序代码。
【范例程序:Review_scores.py】成绩单统计小帮手
01 # -*- coding: utf-8 -*- 02 """ 03 程序名称:成绩单统计小帮手 04 题目要求: 05 读入CSV文件 06 列出总和、平均分以及等级(甲、乙、丙、丁) 07 甲:平均80~100分 08 乙:平均60~79分 09 丙:平均50~59分 10 丁:平均50分以下 11 """ 12 import csv 13 14 print("{0:<3}{1:<5}{2:<4}{3:<5}{4:<5}".format("", "姓名", "总分", "平均分", "等级")) 15 with open("scores.csv",encoding="utf-8") as csvfile: 16 x = 0 17 for row in csv.reader(csvfile): 18 19 if x > 0: 20 scoreTotal = int(row[1]) + int(row[2]) + int(row[3]) 21 average = round(scoreTotal / 3, 1) 22 23 if average >= 80 : 24 grade = "甲" 25 elif 60 <= average < 80: 26 grade = "乙" 27 elif 50 <= average < 60: 28 grade = "丙" 29 else: 30 grade = "丁" 31 32 print("{0:<3}{1:<5}{2:<5}{3:<6}{4:<5}".format(x, row[0], scoreTotal, average, grade)) 33 34 x += 1