python 学习简记 《编程导论》 CH8&CH9

《编程导论》 CH8 类和面向对象编程

8.1 抽象的数据类型和类

抽象的数据类型vs接口

降低改动程序的复杂度->解耦&抽象

Python中使用类来实现数据抽象

例子:intSet类的定义来实现一个简单的整数集合抽象

class IntSet(object):                                      #类开头是class关键字;IntSet是object的子类
    """intSet is a group of integer"""
    def __init__(self):                    #类被实例化是会调用类中定义的__init__方法,init前后各两根_
        """create a blank int list"""
        self.vals = []

    def insert(self,e):
        """assume e is an integer, insert e into self"""
        if not e in self.vals:
            self.vals.append(e)

    def member(self,e):
        """assume e is an integer,
                if e in self return true, else return false"""
        return e in self.vals

    def remove(self,e):
        """assume e is an integer, delete e from self,
                if e is not in self throw ValueError exception"""
        try:
            self.vals.remove(e)
        except:
            raise ValueError(str(e) + ' not found')

    def getMember(self):
        """return a list which contains elements in self.
                the order of the elements cannot be assumed."""
        return self.val[:]

    def __str__(self):                             #当使用print语句时,和类关联的__str__函数会被自动调用
        """return the string form of self"""
        self.vals.sort()
        result = ''
        for e in self.vals:
            result = result + str(e) + ','
        return '{'+result[:-1]+'}' #-1 omits trailing comma

定义一个类会创建一个type类型的对象并给它关联一些instancemethod(实例方法)类型的对象。如,表达式IntSet.insert引用的是IntSet类中定义的insert方法。

代码: print type(IntSet),type(IntSet.insert)

会输出: <type 'type'> <type 'instancemethod'>

类中出现函数定义,这个函数会被称为方法并和这个类关联起来。->方法属性 vs 数据属性(vals)

类支持两类操作:

实例化:用来创建类的实例。如语句S=IntSet()会创建一个类型为IntSet的新对象,此新对象称为IntSet的一个实例。

属性引用:使用点标记法来访问类所关联的属性。如,s.member指的是IntSet的实例s所关联的方法member。

可以使用点标记法来调用和类实例关联的方法,如:

s=IntSet()
s.insert(3)
print s.member(s)

表达式中点号前面的对象会被当作第一个参数传入方法。惯例用self来命名绑定到这个实参的形参。


不应把类和类的实例搞混。属性既可以关联到类本身,也可以关联到类的实例:

方法属性定义在类定义中,如IntSet.member是类IntSet的一个属性。当类被实例化时,例如通过s=IntSet(),实例的属性(如s.member)会被创建。IntSet.member和s.member是不同的对象。在IntSet类的定义中,s.member最初被绑定到member方法上,但是在计算的过程中可以改变这一绑定。

当数据属性被关联到类时称为类变量,被关联到实例时称为实例变量。


表现的独立性->一个抽象类型的实现包含:

·类型方法的实现

·用来表示类型值的数据结构

·关于方法如何使用数据结构的约定->表示的不变性->定义如何通过数据属性表示合法的抽象值


1.使用抽象的数据类型来设计程序

数据抽象鼓励程序设计者关注数据对象的中心性,而非关注函数。

2.使用类来记录学生和教师

import datetime

class Person(object):

    def __init__(self,name):
        """create a preson"""
        self.name = name
        try:
            lastBlank = name.rindex(' ')
            self.lastName = name[lastBlank+1:]
        except:
            self.lastName = name
        self.birthday = None

    def getName(self):
        """return the person's name"""
        return self.name

    def getLastName(self):
        """return the person's last name"""
        return self.lastName

    def setBirthday(self,birthDate):
        """assume the type of birthDate is datetime.date
                set the person's birthday as birthDate"""
        self.birthday = birthDate

    def getAge(self):
        """return the relevant number of days of the person's age"""
        if self.birthday == None:
            raise ValueError
        return (datetime.date.today()-self.birthday).days

    def __lt__(self,other):  #重载小于符号
        """if the dictionary order of the person's name is less than the other's return true,
                else return false"""
        if self.lastName == other.lastName:
            return self.name < other.lastName
        return self.lastName < other.lastName

    def __str__(self):
        """return the person's name"""
        return self.name


me = Person('Michael Guttag')
him = Person('Barack Hussein Obama')
her = Person('Madonna')
print him.getLastName()
him.setBirthday(datetime.date(1961,8,4))
her.setBirthday(datetime.date(1958,8,16))
print him.getName(),'is',him.getAge(),'days old'

pList = [me,him,her]
for p in pList:
    print p
pList.sort()
for p in pList:
    print p

8.2 继承

class MITPerson(Person):
    nextIdNum = 0 #id 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

子类(MITPerson)继承了超类(Person)的属性,子类可以:

·添加新属性

·覆盖超类的属性

1. 多层继承

Python使用保留字pass作为类的代码部分,这个类中只有从超类继承来的属性。

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=('Billy Beaver',1984)
print p5,'is a graduate student is',type(p5) == Grad
print p5,'is an undergraduate student is',type(p5)==UG
结合上面的类,继承关系可以如下描述:

Person-MITPerson-Student-UG

                                            \ G

中间类型Student的作用很巧妙。可以向MITPerson类添加下面的方法:

def isStudent(self):
    return isinstance(self,Student)
isinstance是Python的内建函数。isinstance的第一参数可以是任意对象,但是第二个参数必须是type类型的对象。当且仅当第一个参数是第二个参数的实例时,函数返回True。如isinstance([1,2],list)的值是true。


替代法则

       使用子类来定义类型的层次结构时,子类型应当被看作父类型行为的拓展。可以通过添加新属性或者覆盖继承自超类的属性来实现。

       子类覆盖父类的方法时要小心,超类的重要行为一定要被所有子类支持。如果用户的代码使用超类的一个实例能正确运行,那么使用子类的实例替换掉超类的实例之后仍然应可以正常工作。


8.3 封装和信息隐藏

      下面的代码可以用来记录一组学生的成绩。

class Grades(object):
    def __init__(self):
        self.students=[]
        self.grades={}
        self.isSorted=True

    def addStudent(self,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):
        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[:]

下面的函数使用Grades类生成6.00这门课的学生成绩列表。

def gradeReport(course):
    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 Bucker')
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)

面向对象编程的两个核心概念:

封装:封装是指将数据属性和操作它们的方法捆绑在一起。如:Rafael=MITPerson() 可以使用点标记法来访问Rafael的属性,比如年龄和学号。

信息隐藏:这是模块化的关键。Java&C++等编程语言提供了可以强制隐藏信息的方法。程序猿可以控制类中数据属性的可见性,因此可以强制要求用户代码只能通过对象的属性来访问数据。然而Python没有提供强制隐藏信息的方法。因此无法严格地控制类实例属性的访问。

1.生成器

数据隐藏->性能损失

看上面代码中的gradeReport。调用course.allStudents会创建并返回一个大小为n的列表,n代表学生数量。创建一个已有列表的副本非常低效。一种方法是放弃抽象并允许gradeReport直接访问实例变量course.students,但是这会破坏信息隐藏。幸好还有另一种方法:yield

改进版getStudents:

def getStudents(self):
        if not self.isSorted:
            self.students.sort()
            self.isSorted=True
        for s in self.students:
            yield s

包含yield语句的函数定义会被特殊对待。yield语句会告诉Python函数是一个生成器。生成器通常和for语句一起使用。(要真正理解生成器,需要理解Python内建迭代器的实现方法)。

在for循环的第一次迭代开始时,解释器会执行生成器内部的代码。它会运行到第一个yield语句然后返回yield语句中表达式的值。在下一次迭代时,生成器会从上次返回的位置继续执行,本地变量的绑定也和上次执行时一样。解释器会一直运行到下一个yield语句然后再次跳出。循环会在执行完所有代码或者遇到return语句时退出。

上面的getStudents可以让程序员用for循环来遍历Grades类型对象中的所有学生,就像遍历列表等内建类型的元素一样。举例来说,代码:

book = Grades()
book.addStudent(Grad('Julie'))
book.addStudent(Grad('Charlie'))
for s in book.getStudents():
     print s
会输出:

Julie
Charlie

无论getStudents是一次返回一个列表还是一次生成一个值,for循环都可以进行遍历。一次生成一个值效率更高,因为这样不需要创建新列表。


8.4 进阶实例:抵押贷款

下面的代码比较了三种不同类型的抵押贷款

__author__ = 'sunzhaoyue'

def findPayment(loan,r,m):
    """assume:loan and r are float,m is an integer
    return the money should be refunded when the num of money loaned is loan,
    monthly interest is r in total m months"""
    return loan*((r*(1+r)**m)/((1+r)**m-1))

class Mortgage(object):
    """an abstract class to construct different types of mortgage"""
    def __init__(self,loan,annRate,months):
        self.loan = loan
        self.rate = annRate/12.0
        self.months = months
        self.paid = [0.0]
        self.owed = [loan]
        self.payment = findPayment(loan,self.rate,months)
        self.legend = None #description of mortage

    def makePayment(self):
        """refund"""
        self.paid.append(self.payment)
        reduction = self.payment - self.owed[-1]*self.rate
        self.owed.append(self.owed[-1] - reduction)

    def getTotalPaid(self):
        """return num of money has been repaid now"""
        return sum(self.paid)

    def __str__(self):
        return self.legend

class Fixed(Mortgage):
    def __init__(self,loan,r,months):
        Mortgage.__init__(self,loan,r,months)
        self.legend = 'Fixed, '+str(r*100)+ '%'

class FixedWithPts(Mortgage):
    def __init__(self,loan,r,months,pts):
        Mortgage.__init__(self,loan,r,months)
        self.pts = pts
        self.paid = [loan*(pts/100.0)]
        self.legend = 'Fixed, '+str(r*100)+'%, '+str(pts)+' points'

class TwoRate(Mortgage):
    def __init__(self,loan,r,months,teaserRate,teaserMonths):
        Mortgage.__init__(self,loan,teaserRate,months)
        self.teaserMonths = teaserMonths
        self.teaserRate = teaserRate
        self.nextRate = r/12.0
        self.legend = str(teaserRate*100) + '% for'+str(self.teaserMonths)+' months, then'+str(r*100)+'%'

    def makePayment(self):
        if len(self.paid)==self.teaserMonths+1:
            self.rate = self.nextRate
            self.payment = findPayment(self.owed[-1],self.rate,self.months-self.teaserMonths)
        Mortgage.makePayment(self)

def compareMortgages(amt,years,fixedRate,pts,ptsRate,varRate1,varRate2,varMonths):
    totMonths = years*12
    fixed1 = Fixed(amt, fixedRate, totMonths)
    fixed2 = FixedWithPts(amt, ptsRate, totMonths, pts)
    twoRate = TwoRate(amt, varRate2, totMonths, varRate1, varMonths)
    morts = [fixed1,fixed2,twoRate]
    for m in range(totMonths):
        for mort in morts:
            mort.makePayment()
    for m in morts:
        print m
        print ' Total payments = $' + str(int(m.getTotalPaid()))

compareMortgages(amt=200000, years=30, fixedRate=0.07, pts=3.25,
                 ptsRate=0.05, varRate1=0.045, varRate2=0.095, varMonths=48)

执行代码会输出:

Fixed, 7.0%
 Total payments = $479017
Fixed, 5.0%, 3.25 points
 Total payments = $393011
4.5% for48 months, then9.5%
 Total payments = $551444


CH9   算法复杂度简介


9.1 思考计算复杂度

时间的抽象、解决对输入的依赖

最好情况、最坏情况、平均情况

最坏情况定义了运行时间的上界

9.2 渐进表示

为了量化“大规模”,我们使用渐进表示来描述当输入规模接近无限大时,算法的复杂度。

Big O表示法

9.3 一些重要的复杂度

1.常数复杂度 O(1)

表示渐近复杂度和输入的规模无关。

2.对数复杂度O(log n) 二分查找

3.线性复杂度O(n)  

4.对数线性复杂度 O(n log(n)) 归并排序

5.多项式复杂度

6.指数复杂度

7.复杂度对比


这部分由于数据结构都有介绍,有些东西都很熟悉了,就简单记下

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python的turtle库是一个海龟绘图模块,它是Python自带的标准库,可以通过import语句导入并在Python中使用。海龟绘图源自20世纪60年代的logo语言,它模拟了一个真实的海龟在画布上游走的过程,通过控制海龟的移动和绘画来创建图形。turtle库提供了一些功能函数,包括移动和绘画等操作。你可以使用turtle.fd(d)向前移动一定的距离d,使用turtle.bk(d)向后移动一定的距离d,使用turtle.circle(半径, 弧度)以某个点为圆心绘制曲线等。此外,turtle库还提供了绝对坐标和海龟坐标两种角度坐标体系,你可以通过turtle.seth(angle)来改变海龟的游走方向,也可以通过turtle.left(angle)和turtle.right(angle)以海龟为参考系改变方向。下面是一个示例代码: import turtle turtle.left(45) turtle.fd(150) turtle.right(135) turtle.fd(300) turtle.left(135) turtle.fd(150) 这段代码可以让海龟按照一定的角度和距离绘制出一些图形。通过使用turtle库,你可以使用海龟绘图来进行一些简单的图形绘制和可视化操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Python基础学习简记--海龟绘图(Day10)](https://blog.csdn.net/weixin_39344224/article/details/102807350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [python 学习笔记(三)---turtle库的使用(超详细)](https://blog.csdn.net/qq_40181592/article/details/86770960)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值