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 datetime
class 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.idNum
p1 = 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__(