本文共 15488 字,大约阅读时间需要 51 分钟。
inheritance 指的是不仅要建立class,还要在一个class中建立许多的subclass,让它们都可以共享主class中的standard。
1.1 Using inheritance
import datetimeclass Person(object): def __init__(self, name): '''create a person called name''' self.name = name self.birthday = None self.lastName = name.split(' ')[-1] def getLastName(self): """return self's last name""" return self.lastName def __lt__(self, other): '''return True if self's ame is lexicographically less than other's name, and False otherwise''' if self.lastName == other.lastName: return self.name < other.name return self.lastName < other.lastName def 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 ValueError return (datetime.date.today() - self.birthday).days def __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 -- inheritance nextIdNum = 0 # Next ID number to assign,\ # this is a class attribute, not an attribute for instances def __init__(self, name): Person.__init__(self, name) #initialize Person attributes # new MITPerson attribute: a unique ID number self.idNum = MITPerson.nextIdNum # idNum is an instance attribute # 此处idNum需要调用class attribute nextIdNum的值 MITPerson.nextIdNum += 1 def 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 = name self.incantation = incantation def __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 = Acciospell.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:AccioSummoning Charm AccioNo descriptionConfundus Charm ConfundoCauses 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 = name self.birthday = None self.lastName = name.split(' ')[-1] def getLastName(self): """return self's last name""" return self.lastName def __lt__(self, other): '''return True if self's ame is lexicographically less than other's name, and False otherwise''' if self.lastName == other.lastName: return self.name < other.name return self.lastName < other.lastName def 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 ValueError return (datetime.date.today() - self.birthday).days def __str__(self): """return self's name""" return self.nameclass MITPerson(Person): # This is a subclass of Person -- inheritance nextIdNum = 0 # Next ID number to assign,\ # this is a class attribute, not an attribute for instances def __init__(self, name): Person.__init__(self, name) #initialize Person attributes # new MITPerson attribute: a unique ID number self.idNum = MITPerson.nextIdNum # idNum is an instance attribute # 此处idNum需要调用class attribute nextIdNum的值 MITPerson.nextIdNum += 1 def 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 = classYear def getClass(self): return self.yearclass Grad(MITPerson): # 这里虽然没有定义任何东西,但因为可以直接继承MITPerson中的method和attribute # 此处建立grad的原因是为了区别grad和undergraduate两种学生 passdef isStudent(obj): return isinstance(obj, UG) or isinstance(obj, Grad)
2.3 在hierarchy中如何调用method以及attribute的取值
class A(object): def __init__(self): self.a = 1 def 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 = 2 self.b = 3 def y(self): print "B.y" def z(self): print "B.z"class C(object): def __init__(self): self.a = 4 self.c = 5 def 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 = 6 def 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 = name self.birthday = None self.lastName = name.split(' ')[-1] def getLastName(self): """return self's last name""" return self.lastName def 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 ValueError return (datetime.date.today() - self.birthday).days def __lt__(self, other): """return True if self's ame is lexicographically less than other's name, and False otherwise""" if self.lastName == other.lastName: return self.name < other.name return self.lastName < other.lastName def __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 assign def __init__(self, name): Person.__init__(self, name) # initialize Person attributes # new MITPerson attribute: a unique ID number self.idNum = MITPerson.nextIdNum MITPerson.nextIdNum += 1 def 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 = classYear def 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 objects self.grades = { } # maps idNum -> list of grades # grades这个dictionary的key是学生学号,value是一个list of grades self.isSorted = True # true if self.students is sorted def addStudent(self, student): """Assumes: student is of type Student Add student to the grade book""" 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): """Assumes: grade is a float Add 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 grades return self.grades[student.getIdNum()][:] #just make a copy of the grade list except 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 = True return self.students[:] # return copy of list of studentsdef gradeReport(course): """Assumes: course if of type grades""" report = [] for s in course.allStudents(): tot = 0.0 numGrades = 0 for g in course.getGrades(s): tot += g numGrades += 1 try: average = tot/numGrades report.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 need to 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)
1. definition
def genTest(): yield 1 yield 2> genTest()>>>
next() 的作用是先从程序的开头开始执行,直到reach a “yield” statement,这是会推迟执行,并且返回一个value。
当我们准备好执行接下来的代码时,就再call这个generator的next() function。如果在yield后没有其他语句执行,则会返回一个StopIterationdef genTest(): yield 1 yield 2> foo = genTest()> foo.next()>>> 1 # 返回了第一个yield后面的value> foo.next()>>> 2 # 继续执行了语句,并返回了第二个yield后面的value> foo.next()>>> StopIterationTraceback (most recent call last)in ()----> 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_2 yield next fibn_2 = fibn_1 fibn_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 = 1 while True: next += 1 for p in prime_list: if next % p == 0: break else: 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 = 3 while 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()'''
转载地址:http://yquwi.baihongyu.com/