Lectrue 12

1. Inheritance

inheritance 指的是不仅要建立class,还要在一个class中建立许多的subclass,让它们都可以共享主class中的standard。

1.1 Using inheritance

  • Let’s build an application that organizes info about people!
    – Person: name, birthday

    • Get last name
    • Sort by last name
    • Get age
import datetimeclass Person(object):def __init__(self, name):'''create a person called name'''self.name = nameself.birthday = Noneself.lastName = name.split(' ')[-1]def getLastName(self):"""return self's last name"""return self.lastNamedef __lt__(self, other):'''return True if self's ame is lexicographically less thanother's name, and False otherwise'''if self.lastName == other.lastName:return self.name < other.namereturn self.lastName < other.lastNamedef setBirthday(self,month, day, year):'''sets selfs birthday to birthDate'''self.birthday =datetime.date(year, month, day)def getAge(self):'''returns self's current age in days'''if self.birthday == None:raise ValueErrorreturn (datetime.date.today() - self.birthday).daysdef __str__(self):"""return self's name"""return self.name

1.2 how sort() work in python
用了一个叫做 __lt__的内置method
1.3 进一步丰富此例子

class MITPerson(Person): # This is a subclass of Person -- inheritancenextIdNum = 0 # Next ID number to assign,\# this is a class attribute, not an attribute for instancesdef __init__(self, name):Person.__init__(self, name) #initialize Person attributes# new MITPerson attribute: a unique ID numberself.idNum = MITPerson.nextIdNum # idNum is an instance attribute# 此处idNum需要调用class attribute nextIdNum的值MITPerson.nextIdNum += 1def getIdNum(self):return self.idNum# sorting MIT people uses their ID number, not name!def __lt__(self, other):return self.idNum < other.idNump1 = MITPerson('Eric')
p2 = MITPerson('John')
p3 = MITPerson('John')
p4 = Person('John')>p1 < p2 # 判断哪个在前哪个在后
>>> True
>p3 < p2
>>> False
>p4 < p1
>>> False
>p1 < p4
>>>报错 AttributeError
"""
此处报错的原因在于
This __lt__ method "shadows" the Person method, meaning that if we compare an MITPerson object,since its environment inherits from the MITPerson class environment, Python will see this version of __lt__ not the Person version. 但是反过来,在MITPerson中定义的__lt__method,只有局部的视野,并不能看到Person中定义的__lt__,所以调用会报错。下图更清晰地解释了:
"""


1.4 继承的两个好处(from 廖雪峰教程)

  • 获得父类的全部功能

  • 多态
    当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。(此处run仅为一个例子)
    多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:

对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

对扩展开放:允许新增Animal子类;

对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

1.5 作业题中启示

  • 关于父类与子类的调用关系:
# -*- coding: utf-8 -*-
class Spell(object):def __init__(self, incantation, name):self.name = nameself.incantation = incantationdef __str__(self):return self.name + ' ' + self.incantation + '\n' + self.getDescription()def getDescription(self):return 'No description'def execute(self):print self.incantation    class Accio(Spell):def __init__(self):Spell.__init__(self, 'Accio', 'Summoning Charm')class Confundo(Spell):def __init__(self):Spell.__init__(self, 'Confundo', 'Confundus Charm')def getDescription(self):return 'Causes the victim to become confused and befuddled.'def studySpell(spell):print spellspell = Accio()
# note 这里输出Accio 是因为Spell 的 __init__函数里面的参数写反了!
# note spell 的 name = Summoning Charm incantation = Accio
spell.execute()
# note print函数会去调用 __str__ 将__str__返回的结果输出,
# note __str__ 函数返回的是  Summoning Charm Accio \nNo description  (\n 是换行符号)
studySpell(spell)
# note Confundo 是继承自 Spell的,但是它重载override 了父类的函数, getDescription()
# note 但是由于他没有重载父类的 __str__ 函数,所以print函数依然会调用 Spell里面的__str__ 函数
# note __str__函数里面调用了getDescription函数,因为Confundus自己有getDescription函数,这里会去调用自己的这个函数
# note 返回的就是 Confundus Charm Confundo \n Causes the victim to become confused and befuddled.
studySpell(Confundo())"""
Output:Accio
Summoning Charm Accio
No description
Confundus Charm Confundo
Causes the victim to become confused and befuddled.
"""

2.1 进一步丰富前文例子,形成Class Hierarchy结构

# -*- coding: utf-8 -*-
import datetimeclass Person(object):def __init__(self, name):'''create a person called name'''self.name = nameself.birthday = Noneself.lastName = name.split(' ')[-1]def getLastName(self):"""return self's last name"""return self.lastNamedef __lt__(self, other):'''return True if self's ame is lexicographically less thanother's name, and False otherwise'''if self.lastName == other.lastName:return self.name < other.namereturn self.lastName < other.lastNamedef setBirthday(self,month, day, year):'''sets selfs birthday to birthDate'''self.birthday =datetime.date(year, month, day)def getAge(self):'''returns self's current age in days'''if self.birthday == None:raise ValueErrorreturn (datetime.date.today() - self.birthday).daysdef __str__(self):"""return self's name"""return self.nameclass MITPerson(Person): # This is a subclass of Person -- inheritancenextIdNum = 0 # Next ID number to assign,\# this is a class attribute, not an attribute for instancesdef __init__(self, name):Person.__init__(self, name) #initialize Person attributes# new MITPerson attribute: a unique ID numberself.idNum = MITPerson.nextIdNum # idNum is an instance attribute# 此处idNum需要调用class attribute nextIdNum的值MITPerson.nextIdNum += 1def getIdNum(self):return self.idNum# sorting MIT people uses their ID number, not name!def __lt__(self, other):return self.idNum < other.idNumclass UG(MITPerson):def __init__(self, name, classYear):MITPerson.__init__(self, name)self.year = classYeardef getClass(self):return self.yearclass Grad(MITPerson):# 这里虽然没有定义任何东西,但因为可以直接继承MITPerson中的method和attribute# 此处建立grad的原因是为了区别grad和undergraduate两种学生passdef isStudent(obj):return isinstance(obj, UG) or isinstance(obj, Grad)

  • 如果此时需要添加一种transfer student类别,再次进行isStudent校验时就会出现错误,必须要再修改isStudent函数中的判断才行。——> 这时其实最好的办法是改变整个hierarchy,在mitstudent下再建立一个subclass:student,让三种学生都成为student的subclass。如下图所示:


2.2 Be careful when overriding methods in a subclass!

  • Sbusititution principle
    Important behaviors of superclass should be supported by all subclasses

2.3 在hierarchy中如何调用method以及attribute的取值

class A(object):def __init__(self):self.a = 1def x(self):print "A.x"def y(self):print "A.y"def z(self):print "A.z"class B(A):def __init__(self):A.__init__(self)self.a = 2self.b = 3def y(self):print "B.y"def z(self):print "B.z"class C(object):def __init__(self):self.a = 4self.c = 5def y(self):print "C.y"def z(self):print "C.z"class D(C, B):def __init__(self):C.__init__(self)B.__init__(self)self.d = 6def z(self):print "D.z"> obj = D()
# 找attribute的顺序:按照代码执行的顺序,从最下面开始,一层一层往上找
# 先找D,无a;再找C,a = 4;再找B,B找A,a = 1;再找B自己的,a = 2
> print obj.a
>>> 2
> print obj.b
>>> 3
> print obj.c
>>> 5
> print obj.d
>>> 6# 找method的顺序:从最下面开始找,找到的第一个便直接执行,不再继续向上寻找
> obj.x()
>>> A.X
> obj.y()
>>> C.y
> obj.z()
>>> D.z

2.4 继续补全上述代码,并形成完整example- A Gradebook

# -*- coding: utf-8 -*-
# A Gradebookimport datetimeclass Person(object):def __init__(self, name):"""create a person called name"""self.name = nameself.birthday = Noneself.lastName = name.split(' ')[-1]def getLastName(self):"""return self's last name"""return self.lastNamedef setBirthday(self,month,day,year):"""sets self's birthday to birthDate"""self.birthday = datetime.date(year,month,day)def getAge(self):"""returns self's current age in days"""if self.birthday == None:raise ValueErrorreturn (datetime.date.today() - self.birthday).daysdef __lt__(self, other):"""return True if self's ame is lexicographicallyless than other's name, and False otherwise"""if self.lastName == other.lastName:return self.name < other.namereturn self.lastName < other.lastNamedef __str__(self):"""return self's name"""return self.name# me = Person("William Eric Grimson")
# print me
# me.getLastName()
# me.setBirthday(1,2,1927)
# me.getAge()
# her = Person("Cher")
# her.getLastName()
# plist = [me, her]
# for p in plist: print p
# plist.sort()
# for p in plist: print pclass MITPerson(Person):nextIdNum = 0 # next ID number to assigndef __init__(self, name):Person.__init__(self, name) # initialize Person attributes# new MITPerson attribute: a unique ID numberself.idNum = MITPerson.nextIdNumMITPerson.nextIdNum += 1def getIdNum(self):return self.idNum# sorting MIT people uses their ID number, not name!def __lt__(self, other):return self.idNum < other.idNum# p1 = MITPerson('Eric')
# p2 = MITPerson('John')
# p3 = MITPerson('John')
# p4 = Person('John')# print p1# p1.getIdNum()
# p2.getIdNum()
# p1 < p2
# p3 < p2
# p4 < p1# p1 < p4class UG(MITPerson):def __init__(self, name, classYear):MITPerson.__init__(self, name)self.year = classYeardef getClass(self):return self.yearclass Grad(MITPerson):passdef isStudent(obj):return isinstance(obj,UG) or isinstance(obj,Grad)#s1 = UG('Fred', 2016)
#s2 = Grad('Angela')
#isStudent(s1)
#isStudent(s2)class TransferStudent(MITPerson):pass# go back and define
# class Student(MITPerson)
# change inheritance for UG, Grad and TransferStudent
# change def isStudent(obj):
#            return isinstance(obj, Student)class Grades(object):"""A mapping from students to a list of grades"""def __init__(self):"""Create empty grade book"""self.students = [] # list of Student objectsself.grades = {} # maps idNum -> list of grades# grades这个dictionary的key是学生学号,value是一个list of gradesself.isSorted = True # true if self.students is sorteddef addStudent(self, student):"""Assumes: student is of type StudentAdd student to the grade book"""if student in self.students:raise ValueError('Duplicate student')self.students.append(student)self.grades[student.getIdNum()] = []self.isSorted = Falsedef addGrade(self, student, grade):"""Assumes: grade is a floatAdd grade to the list of grades for student"""try:self.grades[student.getIdNum()].append(grade)except KeyError:raise ValueError('Student not in grade book')def getGrades(self, student):"""Return a list of grades for student"""try: # return copy of student's gradesreturn self.grades[student.getIdNum()][:]#just make a copy of the grade listexcept KeyError:raise ValueError('Student not in grade book')def allStudents(self):"""Return a list of the students in the grade book"""if not self.isSorted:self.students.sort()self.isSorted = Truereturn self.students[:]# return copy of list of studentsdef gradeReport(course):"""Assumes: course if of type grades"""report = []for s in course.allStudents():tot = 0.0numGrades = 0for g in course.getGrades(s):tot += gnumGrades += 1try:average = tot/numGradesreport.append(str(s) + '\'s mean grade is '+ str(average))except ZeroDivisionError:report.append(str(s) + ' has no grades')return '\n'.join(report)ug1 = UG('Jane Doe', 2014)
ug2 = UG('John Doe', 2015)
ug3 = UG('David Henry', 2003)
g1 = Grad('John Henry')
g2 = Grad('George Steinbrenner')six00 = Grades()
six00.addStudent(g1)
six00.addStudent(ug2)
six00.addStudent(ug1)
six00.addStudent(g2)for s in six00.allStudents():six00.addGrade(s, 75)
"""
此处若将代码改写为
for s in six00.students:print s
是能得出一样的结果的,
但是倾向于不这么做,因为this violates the data hiding aspect of an object,
and exposes internal representation.
-- If I were to change how I want to represent a grade book, I should only needto change the methods within that object, not external procedures that use it"""
six00.addGrade(g1, 100)
six00.addGrade(g2, 25)six00.addStudent(ug3)# print gradeReport(six00)
3. generator

1. definition

  • Any procedure or method with a yield statement is called a generator
def genTest():yield 1yield 2> genTest()
>>> <generator object genTest at 0x201b 878>
  • Generators have a next() method which starts/resumes execution of the procedure. Inside of generator(在call generator的next()时可能发生的两种情况):
    yield suspends execution and returns a value
    – Returning from a generator raises a StopIteration exception

next() 的作用是先从程序的开头开始执行,直到reach a “yield” statement,这是会推迟执行,并且返回一个value。
当我们准备好执行接下来的代码时,就再call这个generator的next() function。如果在yield后没有其他语句执行,则会返回一个StopIteration

def genTest():yield 1yield 2> foo = genTest()
> foo.next()
>>> 1 # 返回了第一个yield后面的value
> foo.next()
>>> 2 # 继续执行了语句,并返回了第二个yield后面的value
> foo.next()
>>>
StopIterationTraceback (most recent call last)
<ipython-input-43-93eccb67fafc> in <module>()
----> 1 foo.next()StopIteration:

2. 用途

2.1 using inside a looping structure
We can use a generator inside a looping structure, as it will continue until it gets a StopIteration exception:

> for n in genTest():print n
>>> 1
>>> 2
>
# a Fancier example - 计算斐波那契数列
def genFib():fibn_1 = 1 #fib(n-1)fibn_2 = 0 #fib(n-2)while True:#fib(n) = fib(n-1) + fib(n-2)next = fibn_1 + fibn_2yield nextfibn_2 = fibn_1fibn_1 = next# 每次call genFib_instance.next()都会出现数列中下一个数
'''
for n in genFib():print n
# 使用此方法可不断打印出此数列中的数,直到键盘中断为止
'''

** 2.2 Why Generators**

** 相比之下,第一种方法要一次性列出所有人,如果学生很多就会非常低效,而第二种方法每次只给出一个学生的名字,更加的efficient。

2.3 generator例子

'''
Write a generator, genPrimes, that returns the sequence of prime numbers on successive calls to its next() method: 2, 3, 5, 7, 11, ...
如下是两种方法
'''def genPrimes():prime_list = []next = 1while True:next += 1for p in prime_list:if next % p == 0:breakelse:prime_list.append(next)yield next'''
for else 用法:
Loop statements may have an else clause;
it is executed when the loop terminates through exhaustion of the iterable (with for)
or when the condition becomes false (with while),
but not when the loop is terminated by a break statement.
'''def genPrimes():primes = [2]yield primes[0]guess = 3while True:if all(guess%x != 0 for x in primes):primes.append(guess)        if guess == primes[-1]:yield primes[-1]guess += 2
'''
!!!!注意!在使用generator的时候,要先用函数定义一个instance,再调用next(),
而不是直接在generator后面+next。如下方法才是正确的!primeGenerator = genPrimes()
primeGenerator.next()
'''

CS入门学习笔记14-MIT 6.00.1x- Lecture 12 Object Oriented Programming (Class Generator相关推荐

  1. CS入门学习笔记5-MIT 6.00.1x

    MIT 6.00.1x 第五讲-递归Recursion ** iterative algorithms-- 迭代算法 作业一 Write an iterative function iterPower ...

  2. CS入门学习笔记6-MIT 6.00.1x-tuple,list,dictionary

    Lecture 6 对象 截止目前,已学习过的算法: Exhaustive enumeration Guess and check Bisection Divide and conquer 学习过的s ...

  3. python 入门学习笔记14

    ### 列表list #### 创建一个空list (两种方法) empty_list = [] empty_list = list()# 创建一个list simpsons = ['homer', ...

  4. CS入门学习笔记3-廖雪峰python教程-函数

    第4节-函数 函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回 函数的定义与调用 pass语句 pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放 ...

  5. Crypto++入门学习笔记(DES、AES、RSA、SHA-256)

    Crypto++入门学习笔记(DES.AES.RSA.SHA-256) 背景(只是个人感想,技术上不对后面的内容构成知识性障碍,可以skip): 最近,基于某些原因和需要,笔者需要去了解一下Crypt ...

  6. 汇编入门学习笔记 (十二)—— int指令、port

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...

  7. 计算机指令int,汇编入门学习笔记 (十二)—— int指令、端口

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.端口 参考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引发一 ...

  8. python数据分析入门学习笔记

    python数据分析入门学习笔记儿 学习利用python进行数据分析的笔记儿&下星期二内部交流会要讲的内容,一并分享给大家.博主粗心大意,有什么不对的地方欢迎指正~还有许多尚待完善的地方,待我 ...

  9. Python快速编程入门#学习笔记03# |第二章 :Python基础(代码格式、标识符关键字、变量和数据类型、数字类型以及运算符)

    全文目录 ==先导知识== 学习目标: 2.1 代码格式 2.1.1 注释 2.1.2 缩进 2.1.3 语句换行 2.2 标识符和关键字 2.2.1 标识符 2.2.2 关键字 2.3 变量和数据类 ...

  10. Crypto++入门学习笔记(DES、AES、RSA、SHA-256)(转)

    Crypto++入门学习笔记(DES.AES.RSA.SHA-256)(转) 2012-11-19 11:28:00|  分类: c++|举报|字号 订阅 背景(只是个人感想,技术上不对后面的内容构成 ...

最新文章

  1. tornado 入门
  2. PowerShell2.0之桌面计算机维护(九)磁盘管理
  3. CentOS7开机启动图形界面的开启与关闭
  4. Spring中Bean的生命周期是怎样的?
  5. 广东--阳江--闸波一天游归来,上PP~~
  6. 理科生浪漫起来,谁都顶不住!
  7. 查看idea的安装位置_idea怎么重置默认配置-idea重置默认配置的方法步骤
  8. yum配置(源配置-光驱,ftp服务器;基本用法)
  9. 配置php错误导入文件,php 导入文件(逻辑处理)
  10. 如何用 Python 实时监控文件?方法有三种你喜欢哪一种?
  11. python实现键盘自动输入_如何使用Python实现自动化点击鼠标和操作键盘?
  12. 【图像检索】基于Hu不变矩图像检索含Matlab源码
  13. 坚果pro2刷原生android,坚果Pro2普通版(U3 Pro)魔趣OS 安卓10 纯净完美 原生极简 纯净推荐...
  14. 软考(中级软件设计师)考试信息
  15. 营销科学学会2021年年会揭晓玫琳凯博士论文奖得主
  16. 【JAVA】滴滴-2021校招在线笔试-DE数据开发试卷-0913
  17. Java基础 (适合新手入门保姆级)
  18. CSS3 自定义动画(animation)
  19. 计算机命令提示符开热点,win7系统使用cmd命令创建wifi热点的方法
  20. 应用白名单:方法与挑战

热门文章

  1. Math类的常用函数总结
  2. Excel单元格显示数据与实际数据不一致的设置与清除
  3. X5平台开发的 团队看板 部分代码
  4. Gitlab和gitlab-runner安装和注册
  5. matlab 如何设置工作路径
  6. 解决/**/嵌套问题---条件编译:#if 0 statement #endif 帅帅哒洋办法
  7. 服务器是否支持虚拟化,如何检查服务器CPU是否支持虚拟化技术(VT)
  8. Markdown编辑器简单大概语法学习
  9. 驾考——科一,三笔记
  10. Error:(list) object cannot be coerced to type 'double'的处理