您的位置:首页 > 编程语言 > Python开发

阿齐兹的Python学习笔记——定制数据对象

2018-02-06 22:03 489 查看

定制数据对象

选择的数据结构要与数据匹配,Python中提供了列表、集合、字典和class语句

字典可以将数据与名关联而不是与数字关联,从而实现快速查找

class语句允许你定义自己的数据结构

使用字典关联数据

字典:这是一个内置的数据结构(内置于Python中),允许将数据与键而不是数字关联。这样可以使内存中的数据与实际数据的结构保持一致

使用一个Python字典,将数据值与键关联:

Name —— “Sarah Sweeney”

DOB —— “2002-6-17”

Times —— [‘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字典在其他编程语言中还有不同的名字,例如“映射”、“散列”和“关联数组”,实际上指的就是字典

可以使用一个大括号创建字典,也可以使用一个工厂函数
dict()
创建:

>>> cleese = {}
>>> palin = dict()
>>> type(cleese)
<class 'dict'>
>>> type(palin)
<class 'dict'>


每个字典都有一个Name和Occupations列表。通过将键与值关联,可以向字典分别增加一些数据,也可以一次性创建

>>> cleese['Name'] = 'John Cleese'
>>> cleese['Occupations'] = ['actor', 'comedian', 'writer', 'film producer']
>>> palin = {'Name': 'Michael Palin', 'Occupations': ['comedian', 'actor', 'write', 'tv']}


可以以键为索引访问指定字典中的数据项

使用数字来访问存储在一个特定字典键位置上的列表项,可以把它看作“索引串链”

>>> palin['Name']
'Michael Palin'
>>> cleese['Occupations'][-1]
'film producer'


Python字典可以动态扩展来存储额外的键/值对

与列表不同,Python不会维持插入的顺序,因为重点是关联关系

>>> palin['Birthplace'] = "Broomhill, Sheffield, England"
>>> cleese['Birthplace'] = "Weston-super-Mare, North Somerset, England"
>>> palin
{'Name': 'Michael Palin', 'Occupations': ['comedian', 'actor', 'write', 'tv'], 'Birthplace': 'Broomhill, Sheffield, England'}
>>> cleese
{'Name': 'John Cleese', 'Occupations': ['actor', 'comedian', 'writer', 'film producer'], 'Birthplace': 'Weston-super-Mare, North Somerset, England'}


使用字典改进有关训练数据的程序:

import os
os.chdir('C:/Users/0AQZ0/Documents/exercisecode/Python/HeadFirstPython/chapter6')

def sanitize(time_string):
"""this funciton can formalize your data in the format: mins + '.' +secs"""
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 err:
print('File error: ' + str(err))
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'] = sarah
print(sarah_data['Name'] + "'s fastest times are: " + str(sorted(set([sanitize(t) for t in sarah_data['Times']]))[0:3]))


改进
get_coach_data()
函数一次性完成字典的创建:

import os
os.chdir('C:/Users/0AQZ0/Documents/exercisecode/Python/HeadFirstPython/chapter6')

def sanitize(time_string):
"""this funciton can formalize your data in the format: mins + '.' +secs"""
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 err:
print('File error: ' + str(err))
return(None)

sarah = get_coach_data('sarah2.txt')
print(sarah['Name'] + "'s fastest times are: " + sarah['Times'])


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

把代码和数据放在一起是对的

函数只有在与数据关联时才有意义,函数通常特定于某些数据,而不是一般的通用函数

Python允许创建并定义面向对象的类,类可以用来将代码与代码处理的数据相关联

使用类的好处:

1. 使用类有助于降低复杂性

2. 降低复杂性意味着bug更少

3. bug更少意味着代码更可维护

定义一个类

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

一些基本概念:

类的方法(method):你的代码

类的属性(attribute):数据

实例(instance):实例化的数据对象

每个对象都由类创建,并共享一组类似的特性。各个实例中的方法(代码)都相同,但是各个对象的属性(数据)不同,因为属性由原始数据创建

使用class定义类

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

class Athlete:
def __init__(self):
#The code to initialize a "Athlete" object.
......


“init”前面和后面分别有两个下划线

创建对象实例

创建对象实例,只需将对类名的调用赋至各个变量。通过这种方式,类(以及
__init__()
方法)提供了一种机制,允许你创建一个定制的工厂函数,用来跟据需要创建多个对象实例

a = Athlete()
b = Athlete()
c = Athlete()
d = Athlete()


小括号告诉Python要创建一个新的“Athlete”对象,并赋给一个变量

__init__()
方法可以定制对象的初始状态

self的重要性

定义一个类时,实际上是在定义一个定制工厂函数,然后可以使用它来创建实例

a = Athlete()


a:目标标识符,包含实例的一个引用

Athlete():调用类的定制工厂函数

Python处理这行代码时,目标标识符会赋至self参数

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

Athlete().__init__(a)


每个方法的第一个参数都是self

不仅
__init__()
方法需要self作为它的第一个参数,类中定义的所有其他方法都是如此

Python要求每个方法的第一个参数为调用对象实例

class Athlete:
def __init__(self, value=0):
self.thing = value
def how_big(self):
return(len(self.thing))


每个方法都使用self标识调用对象实例

初始化代码将所提供的一个值赋至一个名为self.thing的类属性

d = Athlete('Holy Grail')
d.how_big()


等效于

Athlete.__init__(d, 'Holy Grail')
Athlete.how_big(d)


其中Athlete是类,
__init__()
how_big()
是方法

示例:

定义一个类

>>> class Athlete:
def __init__(self, a_name, a_dob=None, a_times=[]):
self.name = a_name
self.dob = a_dob
self.times = a_times

>>> sarah =Athlete('Sarah Sweeney', '2002-6-17', ['2:58', '2.58', '1.56'])
>>> james = Athlete('James Jones') #james使用缺省值
>>> type(sarah)
<class '__main__.Athlete'>
>>> type(james)
<class '__main__.Athlete'>


sarah和james的内存地址不同

>>> serah
<__main__.Athlete object at 0x0000011C6A31A828>
>>> james
<__main__.Athlete object at 0x0000011C6A3ADE80>


可以使用点记法来访问各个与对象实例关联的属性

>>> serah.name
'Sarah Sweeney'
>>> james.name
'James Jones'
>>> serah.dob
'2002-6-17'
>>> james.dob #james对象实例没有dob值,所以屏幕上不显示任何内容
>>> serah.times
['2:58', '2.58', '1.56']
>>> james.times
[]


使用类定义改进有关训练数据的程序

import os
os.chdir('C:/Users/0AQZ0/Documents/exercisecode/Python/HeadFirstPython/chapter6')

def sanitize(time_string):
"""this funciton can formalize your data in the format: mins + '.' +secs"""
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 err:
print('File error: ' + str(err))
return(None)

sarah = get_coach_data('sarah2.txt')
print(sarah.name + "'s fastest times are: " + str(sarah.top3()))


更多功能==更多方法

只需增加方法将你需要的新功能封装在类中,一个类可以有多少个方法根本没有限制

值得注意的问题

top3()
方法返回一个列表,而不是一个字符串,这么做可以更加灵活,因为不是所以程序都希望处理字符串

不直接把最快的3个时间作为一个属性存储在类中,也是为了灵活性,因为假如增加更多的数据,top3()方法可以动态地计算最快的3个时间

在各个对象的属性中保留原始数据,可以支持类的扩展来满足将来的其他需求

为了向现有对象中增加更多的数据,可以定义一个方法来增加一个数据或者一个列表

如果改变类的实现,或者利用类实现的内部细节,将会破坏原先使用这个类的所有代码

使用面向对象的原因之一就是要对类的用户隐藏类实现的细节,定义你的API正是充分支持了这个设计理念。倘若暴露类实现的内部细节,或者希望程序员利用类的实现细节,会很大程度上破坏面向对象的基本理念

定义新的方法来向现有对象中增加更多的数据

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)


继承Python内置的list

class允许你从零开始创建一个定制类,还允许通过继承现有的其他类来创建一个类,这包括用list、set、dict提供的Python内置数据结构类

通过继承创建的这些类称为子类

从一个现有的类(如list)继承时,它会为你提供所有现有的功能

定义一个子类

>>> class NamedList(list):
def __init__(self, a_name):
list.__init__([])
self.name = a_name


list提供一个类名,新类将派生这个类

__init__()
中还要增加初始化所派生的类这一步

创建一个对象实例

>>> johnny = NamedList("John Paul Jones")
>>> type(johnny)
<class '__main__.NamedList'>
>>> dir(johnny)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'name', 'pop', 'remove', 'reverse', 'sort']


johnny可以做列表能做的所有事情,还可以在name属性中存储数据

可以对johnny使用list类提供的功能,也可以对johnny做列表处理

>>> johnny.append("Bass Player")
>>> johnny.extend(["Composer", "Arranger", "Musician"])
>>> johnny
['Bass Player', 'Composer', 'Arranger', 'Musician']
>>> johnny.name
'John Paul Jones'
>>> for attr in johnny:
print(johnny.name + " is a " + attr + ".")

John Paul Jones is a Bass Player.
John Paul Jones is a Composer.
John Paul Jones is a Arranger.
John Paul Jones is a Musician.


用继承list的子类改进关于训练数据的程序

import os
os.chdir('C:/Users/0AQZ0/Documents/exercisecode/Python/HeadFirstPython/chapter6')

def sanitize(time_string):
"""this funciton can formalize your data in the format: mins + '.' +secs"""
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 err:
print('File error: ' + str(err))
return(None)

sarah = get_coach_data('sarah2.txt')
print(sarah.name + "'s fastest times are: " + str(sarah.top3()))


值得注意的问题

可以从任何内置的类型继承

Python支持多重继承

可以从自己定制的类继承。你可以创建一个一般化的类,然后派生子类来提高更特定、更有针对性的功能

可以把类放在模块中,在多个程序中共享这个类。如果把AthleteList类保存在athletelist.py中,可以使用
from athletelist import AthleteList
这行代码导入这个类

小结

如何创建一个字典:dict()、{}

如何访问一个字典:中括号记法

字典的动态扩大:键值对形式的扩大

如何填充一个字典:一个一个/一次性

用class关键字定义一个类,
__init__
方法

self参数的作用

如何继承一个内置的类或者定制的类
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python