《Head First Python》第六章--定制数据对象

先上数据集: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:

  • 使用dict()工厂函数或{}可以创建一个空字典
  • 要访问一个名为person的字典中与键Name关联的值,可以使用我们熟悉的中括号记法:person['Name']
  • 类似于列表和集合,Python的字典会随着新数据增加到这个数据结构中而动态扩大。
  • 可以创建一个空字典然后增加数据,也可以一次完成操作。
  • 可以用class关键字定义一个类。
  • 类方法(代码)与函数的定义基本相同,也就是说,要用def定义。
  • 类属性(数据)就像是对象实例中的变量。
  • 可以类中定__init__()方法来初始化对象实例。
  • 类中定义的每个方法都必须有self,从而将数据于其实例相关联。

你可能感兴趣的:(Python)