先上数据集:Head First Python 数据集
第六章的数据在第五章的基础上加了两个属性:姓名和出生日期
james2.txt
James Lee,2002-3-14,2-34,3:21,2.34,2.45,3.01,2:01,2:01,3:10,2-22,2-01,2.01,2:16
上一章的思路依然没有问题,还是按照逗号拆分成列表,不过需要多出两个变量来保存姓名和出生日期。如果对每个运动员都创建两个变量,四个运动员就是8个变量,10个运动员就得20个变量,这并不合理。而且这些数据之间是有联系的,它们都跟同一个人相关,列表也无法体现这种关联性。
方法一:数据字典
首先我们采用Python内置的一种数据结构:字典,字典将键与数据相关联,可以使内存中的数据和实际数据的结构保持一致。
创建字典的两种方式:
一、james = {}
二、james = dict()
james['name'] = 'James Lee' 这就是字典中的一个键值对
下面是本章的第一种数据处理方法:
# 格式化字符串
def sanitize(time_string):
if('-' in time_string):
splitter = '-'
elif(':' in time_string):
splitter = ':'
else:
return (time_string)
(mins, secs) = time_string.split(splitter)
return (mins + '.' + secs)
# 从文件读取训练数据
def get_coach_data(filename):
# 创建一个字典接受返回值
mydic = {}
try:
with open(filename) as myfile:
# 把读到的数据按','分隔成一个列表
data = myfile.readline().strip().split(',')
# 取前两个数据(pop(0)删除并返回最前面的数据项)
mydic['name'] = data.pop(0)
mydic['DOB'] = data.pop(0)
# 对后面的数据进行格式化,并取最小的三个数据
mydic['top3'] = str(sorted(set([sanitize(d) for d in data]))[0:3])
except IOError as ioerr:
# 文件异常
print('File Error: ' + str(ioerr))
return (None)
# 返回字典
return (mydic)
# 输出james的最好的三次数据
james = get_coach_data('james2.txt')
print(james['name'] + "`s faster times are : " + james['top3'])
# 输出julie的最好的三次数据
julie = get_coach_data('julie2.txt')
print(julie['name'] + "`s faster times are : " + julie['top3'])
# 输出mikey的最好的三次数据
mikey = get_coach_data('mikey2.txt')
print(mikey['name'] + "`s faster times are : " + mikey['top3'])
# 输出sarah的最好的三次数据
sarah = get_coach_data('sarah2.txt')
print(sarah['name'] + "`s faster times are : " + sarah['top3'])
运行结果如图:
方法二:定义一个类,利用类对象来体现数据结构关系
Python使用class定义类。每个定义的类都有一个特殊的方法,名为__init__(),可以通过这个方法控制如何初始化对象。
类中的和函数的定义类似,同样是使用def来定义。
Python要求每个方法的第一个参数为调用对象实例,也就是说每个方法的第一个参数都是self。
这样我们就可以对运动员数据进行封装:
class Athlete:
# 构造方法,至少要提供一个name值
def __init__(self, a_name, a_dob=None, a_times=[]):
self.name = a_name
self.dob = a_dob
self.times = a_times
# 获取最快的三次记录
def top3(self):
return (str(sorted(set([sanitize(d) for d in self.times]))[0:3]))
Athlete类包含三个属性,其中name属性是必须提供的,dob和times是缺省的。
完整代码如下:
class Athlete:
# 构造方法,至少要提供一个name值
def __init__(self, a_name, a_dob=None, a_times=[]):
self.name = a_name
self.dob = a_dob
self.times = a_times
# 获取最快的三次记录
def top3(self):
return (str(sorted(set([sanitize(d) for d in self.times]))[0:3]))
# 格式化字符串
def sanitize(time_string):
if('-' in time_string):
splitter = '-'
elif(':' in time_string):
splitter = ':'
else:
return (time_string)
(mins, secs) = time_string.split(splitter)
return (mins + '.' + secs)
# 从文件读取训练数据
def get_coach_data(filename):
try:
with open(filename) as myfile:
# 把读到的数据按','分隔成一个列表
data = myfile.readline().strip().split(',')
# 返回一个Athlete对象
return (Athlete(data.pop(0), data.pop(0), data))
except IOError as ioerr:
# 文件异常
print('File Error: ' + str(ioerr))
return (None)
james = get_coach_data('james2.txt')
print(james.name + "`s faster times are : " + james.top3())
julie = get_coach_data('julie2.txt')
print(julie.name + "`s faster times are : " + julie.top3())
mikey = get_coach_data('mikey2.txt')
print(mikey.name + "`s faster times are : " + mikey.top3())
sarah = get_coach_data('sarah2.txt')
print(sarah.name + "`s faster times are : " + sarah.top3())
运行结果如图:
对于运动员来说,每次训练完都会有新的数据产生,如果要想把新的数据添加进去,就需要写新的方法来做这件事(Python中属性是私有的,外部不可直接访问修改,而方法是公有的,所以可以通过方法来修改数据)。
面对这种情况,我们介绍第三种处理数据的方法:继承内置类
其实,到我们封装成类之后,Athlete的times还是用list来存储的,既然是对times的修改,那么我们能不能继承list呢?这样就可以使用list的方法,append,extend等。
类继承:
class AthleteList(list):
def __init__(self, a_name, a_dob=None, a_times=[]):
list.__init__([])
self.name = a_name
self.dob = a_dob
self.extend(a_times)
# 获取最快的三次记录
def top3(self):
return (str(sorted(set([sanitize(d) for d in self]))[0:3]))
AthleteList继承自list,比list多了两个属性name和dob,而训练数据直接用AthleteList自身(从list那继承过来的属性)来存储。
完整代码:
class AthleteList(list):
def __init__(self, a_name, a_dob=None, a_times=[]):
list.__init__([])
self.name = a_name
self.dob = a_dob
self.extend(a_times)
# 获取最快的三次记录
def top3(self):
return (str(sorted(set([sanitize(d) for d in self]))[0:3]))
# 格式化字符串
def sanitize(time_string):
if('-' in time_string):
splitter = '-'
elif(':' in time_string):
splitter = ':'
else:
return (time_string)
(mins, secs) = time_string.split(splitter)
return (mins + '.' + secs)
# 从文件读取训练数据
def get_coach_data(filename):
try:
with open(filename) as myfile:
# 把读到的数据按','分隔成一个列表
data = myfile.readline().strip().split(',')
# 返回一个Athlete对象
return (AthleteList(data.pop(0), data.pop(0), data))
except IOError as ioerr:
# 文件异常
print('File Error: ' + str(ioerr))
return (None)
james = get_coach_data('james2.txt')
james.append('2.00')
print(james.name + "`s faster times are : " + james.top3())
julie = get_coach_data('julie2.txt')
julie.extend(['2-13', '2:18'])
print(julie.name + "`s faster times are : " + julie.top3())
mikey = get_coach_data('mikey2.txt')
print(mikey.name + "`s faster times are : " + mikey.top3())
sarah = get_coach_data('sarah2.txt')
print(sarah.name + "`s faster times are : " + sarah.top3())
代码中还顺便测了下从list哪儿继承过来的方法append和extend。
运行结果如图:
BULLET POINTS: