一、继承父类属性和方法
1. 继承
面向对象的编程带来的好处之一是代码的重用,实现这种重用方法之一是通过继承机制。继承(Inheritance)是两个类或多个类之间的父子关系,子类继承了父类的所有公有数据属性和方法,并且可以通过编写子类的代码扩充子类的功能。想象一下,如果人类可以做到子女继承父母的所有才学并加以扩展,那么人类的发展至少是现在的数万倍。继承实现了数据属性和方法的重用,减少了代码的冗余度。
在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承自狗。
特定狗种类继承狗类,狗类继承动物类,狗类编写了描述所有狗种共有的行为和方法,而特定狗种类则增加了该狗种特有的行为。不过继承也有一定弊端,可能父类对于子类也有一定特殊的地方,如某种特定狗种不具有绝大部分狗种的行为,当程序员没有理清类间的关系时,可能使得子类具有了不该有的方法。另外,如果继承链太长的话,任何一点小的变化都会引起一连串变化,使用的继承要注意控制继承链的规模。
在Python中继承有以下一些特点。
(1) 在继承中基类初始化方法__init__不会被自动调用。如果希望子类调用基类的__init__方法,需要在子类的__init__方法显示调用它。这与C++和C#区别很大。
(2) 在调用基类的方法时,需要加上基类的类名前缀,且带上self参数变量。注意在类中调用在该类定义的方法是不需要self参数的。
(3) Python总是首先查找对应类的方法,如果在子类没有对应的方法,Python才会在继承链的基类中按顺序查找。
(4) 在Python继承中,子类不能访问基类的私有成员。
最后一次修改类Cat的代码。
>>>class Cat():
... def __init__(self):
... self.name = '猫'
... self.age = 4
... self.info = [self.name,self.age]
... self.index = -1
... def run(self):
... print( self.name,'--在跑')
... def getName(self):
... return self.name
... def getAge(self):
... return self.age
... def __iter__(self):
... print('名字 年龄')
... return self
... def next(self):
... if self.index == len(self.info)-1:
... raise StopIteration
... self.index += 1
... return self.info[self.index]
>>>class Bosi(Cat):
... def setName(self, newName):
... self.name = newName
... def eat(self):
... print( self.name,'--在吃')
...
>>>bs = Bosi() # 创建对象
>>>print( 'bs的名字为:',bs.name) # 继承父类的属性和方法
bs的名字为: 猫
>>>print( 'bs的年龄为:',bs.age)
bs的年龄为: 4
>>>print(bs.run())
猫 --在跑
>>>bs.setName('波斯猫') # 子类的属性和方法
>>>bs.eat()
波斯猫 --在吃
>>>iterator = iter(bs.next,1) # 迭代输出父类的属性
>>>for info in iterator:
... print(info)
猫
4
定义了Bosi类的父类Cat,将猫共有的属性和方法都放到父类中,子类仅仅需要向父类传输数据属性即可。这样做可以很轻松地定义其他基于Cat类的子类。因为假如有数百只猫,使用继承的方法大大减少了代码量,且当需要对全部猫整体修改时仅需要修改Cat类即可。Bosi类的__init__函数中显示调用了Cat类的__init__函数,并向父类传输数据,这里注意要加self参数。
在继承里面不能继承父类的私有属性,所以也不用担心父类和子类出现因继承造成的重名情况。为了能更清晰地讲述这个问题,这里再举一个例子。
>>>class animal():
... def __init__(self,age):
... self.__age = age
... def print2(self):
... print(self.__age)
>>>class dog(animal):
... def __init__(self,age):
... animal.__init__(self,age)
... def print2(self):
... print(self.__age)
>>>a_animal = animal(10)
>>>a_animal.print2()
10
>>>a_dog = dog(10)
>>>a_dog.print2() # 程序报错
AttributeError: 'dog' object has no attribute '_dog__age'
2. 多继承
如果有多个父类,则父类名需要全部都写在括号里,这种情况称为多继承,格式为Class子类名(父类名1,父类名2,•••)。
>>>class A(object): # 定义一个父类
... def __init__(self):
... print (" ->Input A")
... print (" <-Output A")
>>>class B(A): # 定义一个子类
... def __init__(self):
... print (" -->Input B")
... A.__init__(self)
... print (" <--Output B")
>>>class C(A): # 定义另一个子类
... def __init__(self):
... print (" --->Input C")
... A.__init__(self)
... print (" <---Output C")
>>>class D(B, C): # 定义一个子类
... def __init__(self):
... print ("---->Input D")
... B.__init__(self)
... C.__init__(self)
... print ("<----Output D")
>>>d = D() # Python中是可以多继承的,父类中的方法、属性,子类会继承。
---->Input D
-->Input B
->Input A
<-Output A
<--Output B
--->Input C
->Input A
<-Output A
<---Output C
<----Output D
>>>issubclass(C,B) # 判断一个类是不是另一个类的子孙类
False
>>>issubclass(C,A)
True
实现继承之后,子类将继承父类的属性,也可以使用内建函数issubclass函数来判断一个类是不是另一个类的子孙类,前项参数为子类,后项参数为父类。
二、掌握其他方法
面向对象的三大特性是指重载、封装和多态。
1. 重载
所谓重载,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法。
>>>class Cat:
... def sayHello(self):
... print("喵-----1")
>>>class Bosi(Cat):
... def sayHello(self):
... print("喵喵----2")
>>>bosi = Bosi()
>>>bosi.sayHello() # 子类中的方法会覆盖掉父类中同名的方法
喵喵----2
2. 封装
既然Cat实例本身就拥有这些数据,要访问这些数据,就没有必要从外面的函数去访问,可以直接在Cat类的内部定义访问数据的函数。这样,就把数据给“封装”起来了。
封装(Encapsulation)就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体(即类);封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是通过外部接口,特定的访问权限来使用类即可。简而言之,就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
3. 多态
多态性(Polymorphism)是对象通过他们共同的属性和动作来操作及访问,允许将父对象设置成和一个或多个它的子对象相等的技术,比如Car=Land_Rover。多态性使得能够利用同一类(父类)类型的指针来引用不同类的对象,以及根据所引用对象的不同,以不同的方式执行相同的操作。
Python是动态语言,可以调用实例方法,不检查类型,只要方法存在,参数正确就可以调用,这就是与静态语言(例如Java)最大的差别之一。表明了动态(运行时)绑定的存在,允许重载或运行时类型确定和验证。
三、练习
在创建的Car类上产生子类Land_Rover,要使子类Land_Rover拥有2个父类属性(品牌、颜色)和两个自带属性(车轮数、废气涡轮增压),然后输出子类属性。
参考代码:
class Car():
def __init__(self,brand, newWheelNum, newColor,T):
self.brand = brand
self.wheelNum = newWheelNum
self.color = newColor
self.T = T # T为废气涡轮增压
self.info = [self.brand,self.wheelNum,self.color,self.T]
self.index = -1
def getBrand(self):
return self.brand
def getNewheelnum(self):
return self.wheelNum
def getNewcolor(self):
return self.color
def getT(self):
return self.T
def __iter__(self):
print('品牌 车轮数 颜色 废气涡轮增压')
return self
def next(self):
if self.index == 3:
raise StopIteration
self.index += 1
return self.info[self.index]
class Land_Rover(Car):
def __init__(self,brand, newColor):
self.brand = brand
self.wheelNum = 4
self.color = newColor
self.T = 3
Car.__init__(self,self.brand,self.wheelNum,self.color,self.T)
Luxury_car = Car('BMW',4, 'green',2.4) # 创建对象
print(Luxury_car.getNewcolor()) # 访问属性
iterator = iter(Luxury_car.next,1) # 调用迭代函数
for info in iterator:
print(info)
Python面向对象编程系列文章两周一更!
文章未经博主同意,禁止转载!