抽象数据类型,是指由对象以及对象上的操作组成的集合,捆绑为一个整体,可以传递到程序的另一个部分,可以使用对象数据属性以及使用对象上的操作
目的,使程序易于修改,控制程序复杂程度,两种机制可以完成这个任务:
Python语言中,使用类实现数据抽象,以下是一个类定义,实现对整数集合的抽象:
class IntSet(object):
"""IntSet是一个整数集合"""
# 关于实现的信息
# 集合的值由一个整合组self.vals表示
# 集合中的每个整数在self.vals中只出现一次
def__init__(self):
"""创建一个空的整数集合"""
self.vals = []
def insert(self,e):
if e not in self.vals:
self.vals.append(e)
def member(self,e):
"""假设e是整数
如果e在self中,则返回True,否则返回False"""
return e in self.vals
def remove(self,e):
"""假设e是整数,从self中删除e
如果e不在self中,则抛出ValueError异常"""
try:
self.vals.remove(e)
except:
raise ValueError(str(e) + ' not found')
def getMembers(self):
"""返回一个包含self中元素的列表
对元素不进行排序"""
return self.vals[:]
def __str__(self):
"""返回一个表示self的字符串"""
self.vals.sort()
result = ""
for e in self.vals:
result = result + str(e) + ","
return '{' + result[:-1] + '}'
s = IntSet()
s.insert(3)
print(s.member(3))
# 以上代码可以创建一个实例,并在这个IntSet中插入整数3,然后输出True
类支持两种操作:
Python 中的特殊方法名,__ init__,只要一个类被实例化,就会调用该类中定义的__ init __方法
方法属性定义在类定义中,类被实例化后,实例属性才被创建
数据属性被关联到类时,称其为类变量,数据属性被关联到实例时,将其称为实例变量
表示不变性定义了数据属性中的哪个值对应着类实例的有效表示
import datetime
class Person(object):
def __init__(self, name):
"""创建一个人"""
self.name = name
try:
lastBlank = name.rindex(' ') # 查找子字符串最后出现的位置
self.lastName = name[lastBlank+1:] #分割名字的名与姓
except:
self.lastName = name
self.birthday = None
def getName(self):
"""返回self的全名"""
return self.name
def getLastName(self):
"""返回self的姓"""
return self.lastName
def setBirthday(self, birthdate):
"""假设birthday是datetime.date类型
将self的生日设置为birthday"""
self.birthday = birthdate
def getAge(self):
"""返回self的当前年龄,用日表示"""
if self.birthday == None:
raise ValueError
return (datetime.date.today() - self.birthday).days
def __lt__(self, other): # 相当于less than 简写lt,
***使得实例可以比较,返回bull值***
"""如果self按字母顺序位于other之前,则返回True,否则返回
False。首先按照姓进行比较,如果姓相同,就按照全名比较"""
if self.lastName == other.lastName:
return self.name < other.name
return self.lastName < other.lastName
def __str__(self):
"""返回self的全名"""
return self.name
只要Person被实例化,就要为__init__函数提供一个实参
sort 是一个多态方法,如果plist是有Person类型元素组成的列表,那么调用plist.sort()会定义在Person类中的__lt__方法来对列表进行排序
pList = [me, him, her]
for p in pList:
print(p)
pList.sort()
for p in pList:
print(p)
# 会先输出:
Michael Guttag
Barack Hussein Obama
Madonna
# 再输出:
Michael Guttag
Madonna
Barack Hussein Obama
不同的类型中有许多通用的属性,如list和str 都有len函数
继承使得程序员能够建立一个类型的层次结构,是可以建立一组彼此相关的抽象
如下例子:MITPerson 是Person的一个子类,所以继承了它的超类的属性,除了继承属性外,子类还可以做如下的事:
class MITPerson(Person):
nextIdNum = 0 #identification number
def __init__(self, name):
Person.__init__(self, name)
self.idNum = MITPerson.nextIdNum
MITPerson.nextIdNum += 1
def getIdNum(self):
return self.idNum
def __lt__(self, other):
return self.idNum < other.idNum
def isStudent(self):
return isinstance(self,Student)
p1 = MITPerson('Mark Guttag')
p2 = MITPerson('Billy Bob Beaver')
p3 = MITPerson('Billy Bob Beaver')
p4 = Person('Billy Bob Beaver')
print('p1 < p2 =', p1 < p2)
print('p3 < p2 =', p3 < p2)
print('p4 < p1 =', p4 < p1)
# 输出:
p1 < p2 = True
p3 < p2 = False
p4 < p1 = True
p1,p2,p3都是MITPerson类型,使用MITPerson的__lt__方法,
***调用哪种__lt__方法是有表达式的第一个参数决定的***
p4 和 p1比较时按照名字排序
以下是类层次结构添加了二重继承
结构:
class Student(MITPerson):
pass
class UG(Student):
def __init__(self, name, classYear):
MITPerson.__init__(self, name)
self.year = classYear
def getClass(self):
return self.year
class Grad(Student):
pass
p5 = Grad('Buzz Aldrin')
p6 = UG('Billy Beaver', 1984)
print(p5, 'is a graduate student is', type(p5) == Grad)
print(p5, 'is an undergraduate student is', type(p5) == UG)
#输出:
Buzz Aldrin is a graduate student is True
Buzz Aldrin is an undergraduate student is False
isinstance ()是内置在Python中的,其中第一个参数是任何对象,第二个参数必须是一个type类型的对象
如: isinstance([1, 2], list) 的值是 True
# isStudent()方法在MITPerson中定义
print(p5, 'is a student is', p5.isStudent())
print(p6, 'is a student is', p6.isStudent())
print(p3, 'is a student is', p3.isStudent())
class Grades(object) :
def __init__(self) :
"""创建空的成绩表"""
self.students = []
self.grades = {}
self.isSorted = True
def addStudent(self, student) :
"""假设student为Student类型
将student添加到成绩册"""
if student in self.students :
raise ValueError('Duplicate student')
self.students.append(student)
self.grades[student.getIdNum()] = []
self.isSorted = False
def addGrade(self, student, grade) :
"""假设grade为浮点数
将grade添加到student的成绩列表"""
try:
self.grades[student.getIdNum()].append(grade)
except:
raise ValueError("Student not in mapping")
def getGrades(self, student):
try: # 切记是返回成绩列表的副本
return self.grades[student.getIdNum()][:]
except:
raise ValueError("Student not in mapping")
def getStudents(self) :
if not self.isSorted:
self.students.sort()
self.isSorted = True
return self.students [:]
def gradeReport(course) :
"""假设course 是Grades 类型"""
report = ""
for s in course.getStudents():
tot = 0.0
numGrades = 0
for g in course.getGrades(s):
tot += g
numGrades += 1
try:
average = tot/numGrades
report = report + '\n'\
+ str(s) + '\' s mean grade is ' + str(average)
except ZeroDivisionError:
report = report + '\n'\
+ str(s) + ' has no grades'
return report
ug1 = UG('Jane Doe', 2014)
ug2 = UG('John Doe', 2015)
ug3 = UG('David Henry', 2003)
g1 = Grad('Billy Buckner')
g2 = Grad('Bucky F. Dent')
sixHundred = Grades()
sixHundred.addStudent(ug1)
sixHundred.addStudent(ug2)
sixHundred.addStudent(g1)
sixHundred.addStudent(g2)
for s in sixHundred.getStudents():
sixHundred.addGrade(s, 75)
sixHundred.addGrade(g1, 25)
sixHundred.addGrade(g2, 100)
sixHundred.addStudent(ug3)
print(gradeReport(sixHundred))
# 输出:
Jane Doe's mean grade is 75.0
John Doe's mean grade is 75.0
David Henry has no grades
Billy Buckner's mean grade is 50.0
Bucky F. Dent's mean grade is 87.5
面对对象编程的核心思想
在Python 3中,可以使用命名惯例使属性在类之外不可见。当一个属性的名称以 __ 开头但不以 __ 结束时,这个属性在类外就是不可见的
class infoHiding(object):
def __init__(self):
self.visible = 'Look at me'
self.__alsoVisible__ = 'Look at me too'
self.__invisible = 'Don\'t look at me directly'
def printVisible(self):
print(self.visible)
def printInvisible(self):
print(self.__invisible)
def __printInvisible(self):
print(self.__invisible)
def __printInvisible__(self):
print(self.__invisible)
test = infoHiding()
print(test.visible)
print(test.__alsoVisible__)
print(test.__invisible)
# 输出:
Look at me
Look at me too
Error: 'infoHiding' object has no attribute '__invisible'
# 新版的getStudents
def getStudents(self):
"""按字母顺序每次返回成绩册中的一个学生"""
in alphabetical order"""
if not self.isSorted:
self.students.sort()
self.isSorted = True
for s in self.students:
yield s
输出结果:
Fixed, 7.0%
Total payments = 479017
Fixed, 5.0%, 3.25 points
Total payments = 393011
4.5% for 48 months, then 9.5%
Total payments = $551444