Python初入门(六)(Head First Python 第六章 打包代码与数据 ,字典,类与继承)

来源:互联网 发布:mac自带远程桌面连接 编辑:程序博客网 时间:2024/06/04 19:47

定制数据对象

现有类似这样的数据
Sarah Sweeney,2002-6-17,2:58,2.58,2:39,2-25,2-55,2:54,2.18,2:55,2:55,2:22,2-21,2.22

要怎样才能更好地处理数据呢?

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 f:            data = f.readline()        return(data.strip().split(','))    except IOError as ioerr:        print('File error: ' + str(ioerr))        return(None)sarah = get_coach_data('sarah2.txt')(sarah_name, sarah_dob) = sarah.pop(0), sarah.pop(0)print(sarah_name + "'s fastest times are: " +        str(sorted(set([sanitize(t) for t in sarah]))[0:3]))

pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。obj – 可选参数,要移除列表元素的对象。这里的pop(0)表示删除并返回列表(list)最前面的列表项。

这个程序确实可以达到预期的要求,但是如果是要处理大量的类似的数据,那将是恐怖的事情。
所以我们引入了字典。


使用字典(dictionary)关联数据

对于下面这样的格式
Sarah Sweeney,2002-6-17,2:58,2.58,2:39,2-25,2-55,2:54,2.18,2:55,2:55,2:22,2-21,2.22
我们可以发现对应关系,我们将使用Python字典,将数据值和键关联:
这里写图片描述

不难发现,Python中的字典与java中的Map是相似的。字典是一个内置的数据结构(内置于Python中),允许数据与键而不是数字关联。这样可以使内存中的数据与实际数据的结构保持一致。字典也可称为”映射”,”散列”或者”关联数组”。

要访问一个名为person的字典中与键Name关联的值,可以使用我们熟悉的中括号记法:
person[‘Name’]

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 f:            data = f.readline()        return(data.strip().split(','))    except IOError as ioerr:        print('File error: ' + str(ioerr))        return(None)sarah = get_coach_data('sarah2.txt')sarah_data = {}sarah_data['Name'] = sarah.pop(0)sarah_data['DOB'] = sarah.pop(0)sarah_data['Times'] = sarahprint(sarah_data['Name'] + "'s fastest times are: " +        str(sorted(set([sanitize(t) for t in sarah_data['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 f:            data = f.readline()        templ = data.strip().split(',')        return({'Name' : templ.pop(0),                'DOB'  : templ.pop(0),                'Times': str(sorted(set([sanitize(t) for t in templ]))[0:3])})    except IOError as ioerr:        print('File error: ' + str(ioerr))        return(None)james = get_coach_data('james2.txt')julie = get_coach_data('julie2.txt')mikey = get_coach_data('mikey2.txt')sarah = get_coach_data('sarah2.txt')print(james['Name'] + "'s fastest times are: " + james['Times'])print(julie['Name'] + "'s fastest times are: " + julie['Times'])print(mikey['Name'] + "'s fastest times are: " + mikey['Times'])print(sarah['Name'] + "'s fastest times are: " + sarah['Times'])

这里可以发现,Python并不需要想java一样先创建对象再返回,在return中,字典创建代码成为函数的一部分。

结果如下:
这里写图片描述


将代码及其数据打包在类中

与java等其他编程语言一样,Python允许创建并定义面向对象的类,类可以用来将代码与代码处理的数据相关联。

使用类有助于降低复杂性
通过将代码与代码处理的数据相关联,随着代码基的扩大,可以降低复杂性。这样代码中的bug会更好,这意味着更可维护。

定义一个类
Python遵循标准的面向对象编程模式,提供了一种方法允许将代码及其处理的数据定义为一个类。一旦有了类定义,就可以用它来创建(或实例化)数据对象,它会继承类的特性。

在面向对象里,你的代码通常成为类的方法(method),数据通常成为类的属性(attribute)。实例化的数据对象通常称为实例。

使用class定义类
Python使用class创建对象(这一点和java一样)。每个定义的类都有一个特殊的方法,名为init(),可以通过这个方法控制如何初始化对象。

类中的方法与函数的定义很类似,形式如下:
这里写图片描述

创建对象实例
有了类之后,创建对象实例只需将对类名的调用赋至各个变量。通过这个方法,类(以及init()方法)提供了一种机制,允许你创建一个定制的工厂函数,用来根据需要创建多个对象实例。
这里写图片描述
与java和c++不同,Python没有定义构造函数”new”的概念.Python会为你完成对象创建,然后你可以使用init()方法定制对象的初始状态。

self的重要性
定义一个类时,实际上是在定义一个工厂函数,然后可以在你的代码中使用这工厂函数创建实例:
这里写图片描述

目标标识符赋至self参数
这是一个非常重要的参数赋值。如果没有这个赋值,Python解释器无法得出方法调用要应用到哪个对象实例。注意,类代码设计为所有对象实例间共享:方法是共享的,而属性不共享。self参数可以帮助标识要处理哪个对象实例的数据。

每个方法的第一个参数都是self
实际上,不仅init()方法需要self作为它的第一个参数,类中定义的所有其他方法也是如此。Python要求每个方法的第一个属性为调用对象实例。

下面扩展这个示例类,在一个名为thing的对象属性中存储一个值,具体指将在初始化时设置。另外还要扩充一个方法, 名为how_big(),它会利用len()BIF返回thing的长度:
这里写图片描述

在一个对象实例上调用类方法是,Python要求第一个参数是调用对象实例,这往往赋至各方法的self参数。Python解释器会自动完成转换。
这里写图片描述

看到这里不难发现,Python中的self就是指本身这个类,跟C++和Java中的this 比较类似。

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)class Athlete:    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(sorted(set([sanitize(t) for t in self.times]))[0:3])def get_coach_data(filename):    try:        with open(filename) as f:            data = f.readline()        templ = data.strip().split(',')        return(Athlete(templ.pop(0),templ.pop(0),templ))    except IOError as ioerr:        print('File error: ' + str(ioerr))        return(None)james = get_coach_data('james2.txt')julie = get_coach_data('julie2.txt')mikey = get_coach_data('mikey2.txt')sarah = get_coach_data('sarah2.txt')print(james.name + "'s fastest times are: " + str(james.top3()))print(julie.name + "'s fastest times are: " + str(julie.top3()))print(mikey.name + "'s fastest times are: " + str(mikey.top3()))print(sarah.name + "'s fastest times are: " + str(sarah.top3()))

我们在类中定义了类Athlete,并且为它定义了一个方法top3(),值得注意的是, return(sorted(set([sanitize(t) for t in self.times]))[0:3]),这里使用了self.times。


现在我们来增加类中的方法,第一个名为add_time(),将一个额外的计时值追加到选手的计时数据,第二个方法add_times()会用一个或多个计时值(提供为一个列表)来扩展一个选手的计时数据。

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)class Athlete:    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(sorted(set([sanitize(t) for t in self.times]))[0:3])    def add_time(self,time_value):        self.times.append(time_value)    def add_times(self,list_of_times):        self.times.extend(list_of_times)def get_coach_data(filename):    try:        with open(filename) as f:            data = f.readline()        templ = data.strip().split(',')        return(Athlete(templ.pop(0),templ.pop(0),templ))    except IOError as ioerr:        print('File error: ' + str(ioerr))        return(None)james = get_coach_data('james2.txt')julie = get_coach_data('julie2.txt')mikey = get_coach_data('mikey2.txt')sarah = get_coach_data('sarah2.txt')print(james.name + "'s fastest times are: " + str(james.top3()))print(julie.name + "'s fastest times are: " + str(julie.top3()))print(mikey.name + "'s fastest times are: " + str(mikey.top3()))print(sarah.name + "'s fastest times are: " + str(sarah.top3()))

结果如下:
这里写图片描述

注意,方法的第一个参数一定是self。


继承Python内置的list
Python的class允许你从零开始创建一个定制类,就像创建Athlete类那样。不过,class还允许通过继承现有的其他类来创建一个类,这也包括用list,set和dict提供的Python内置数据结构类。通过继承创建的这些类成为子类。从一个现有的类继承时,会为你提供所有现有的方法。

下面来看看如何继承Python的内置list类。

这里写图片描述
可以看到,NamedList(list)中提供了一个类名list,新类将派生这个类。
list.init([])初始化了所派生的类。

定义了NamedList类之后,用它创建一个对象实例,检查对象的类型的类型(使用type()BIF),看看它会提供什么内容(使用dir(BIF))
这里写图片描述

可以看到johny是一个”NamedList”对象实例。johny可以做列表能做的所有事情,另外还可以在”name”属性中存储数据。

使用list类提供的一些功能来补充johny中存储的数据:
这里写图片描述

因为johny是一个列表,所以可以对它做列表处理:
这里写图片描述

好了,我们已经大致了解了继承,现在来对上面的代码进行改进。

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)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(sorted(set([sanitize(t) for t in self]))[0:3])def get_coach_data(filename):    try:        with open(filename) as f:            data = f.readline()        templ = data.strip().split(',')        return(AthleteList(templ.pop(0), templ.pop(0), templ))    except IOError as ioerr:        print('File error: ' + str(ioerr))        return(None)james = get_coach_data('james2.txt')julie = get_coach_data('julie2.txt')mikey = get_coach_data('mikey2.txt')sarah = get_coach_data('sarah2.txt')print(james.name + "'s fastest times are: " + str(james.top3()))print(julie.name + "'s fastest times are: " + str(julie.top3()))print(mikey.name + "'s fastest times are: " + str(mikey.top3()))print(sarah.name + "'s fastest times are: " + str(sarah.top3()))
阅读全文
0 0
原创粉丝点击