面向对象编程三大特性介绍
上一节中我们讲了面向对象的一些基础知识,这一节我们继续加深 面向对象编程的知识,让大家更深层次的了解面向对象编程
首先讲讲面向对象的三大特性:
封装、继承、多态
一、封装:
封装:将内容封装到某个地方,之后调用的时候直接调用被封装在某处的内容
1、将内容封装到某处:
class People: #定义一个People类
def __init__(self,name,age,sex): #构造方法,
(当实例化对象时,自动执行这个方法)
self.name = name
self.age = age
self.sex = sex
P1 = People('allen','25','male') #实例化对象P1,将"allen"、25、"male"分别封装
到了 P1/self 中的name,age,sex属性中
P2 = People('yyh','18','male') #P2 ,同上
# __init__ 中的self是一个形式参数,在实例化对象P1和P2的过程中,self分别等于P1和P2, 相对于内容被分别封装到了P1和P2中,每个对象都有name、age、sex属性。
2、从某处调用被封装的内容:
通过对象直接调用被封装的内容
class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
P1 = People('allen','25','male')
P2 = People('yyh','18','male')
print P1.name #直接调用P1对象的name属性
print P2.name #直接调用P2对象的name属性
执行结果如下
allen
yyh
通过self间接调用被封装的内容
class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def getInfo(self):
print self.name
print self.age
print self.sex
P1 = People('allen','25','male')
P2 = People('yyh','18','male')
P1.getInfo() #python默认会将P1传给self参数,即P1.getInfo(P1),此时P1=self,
P1.name等于self.name 是allen;self.age 是25;self.name 是male
P2.getInfo() #同上
二、继承:
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
class Fruit:
def __init__(self,color):
self.color = color
print "fruit's color: %s" %self.color
def grow(self):
print "This is grow ..."
class Apple(Fruit): #继承了父类
def __init__(self, color): #显示调用父类的__init__方法
Fruit.__init__(self, color)
print "apple's color: %s" % self.color
class Banana(Fruit): #继承了父类
def __init__(self,color): #显示调用父类的__init__方法
Fruit.__init__(self,color)
print "banana's color:%s" % self.color
def grow(self): #覆盖了父类的grow方法
print "banana grow..."
apple = Apple('red')
apple.grow()
banana = Banana('yellow')
banana.grow()
执行结果如下:
fruit's color: red
apple's color: red
This is grow ...
fruit's color: yellow
banana's color:yellow
banana grow... #覆盖了父类的grow 方法
对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而
不必一一实现每个方法。
那么问题来了,多继承如何做?
是否可以继承多个类?
如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?
对于多继承中,就要区分经典类和新式类,我上面写的例子都是经典类的写法,
对于新式类,要在类名后的括号中写上object,即class className(object),
object 也是一个类,class className(object),相对于继承了object 类,
则这个类称为新式类,新式类是我们今后推荐的写法
当类是经典类时,多继承情况下,会按照深度优先方式查找
当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类多继承例子:
class D: #经典类
def bar1(self):
print "D.bar1"
class C(D):
def bar1(self):
print "C.bar1"
class B(D):
# def bar1(self):
# print "B.bar1"
pass #pass 代表什么也不做
class A(B,C):
# def bar1(self):
# print "A.bar1"
pass #pass 代表什么也不做
op = A() #实例化对象op
op.bar1() #访问op中bar1方法,但是具体访问到哪个方法呢???
执行结果如下:
D.bar1 #为什么是访问到了D.bar1 ? ,
分析如下:
当我们实例化op,并且调用bar1方法时,由于在类中有多个bar1方法,因此对于经典类,它自己
有一个查找顺序,A ---> B --> D --> C, 什么意思呢?
我们分析一下:
首先找A,如果A中没有,则找B,如果B中没有,再找D,如果D中也没有,最后找C,都没有找到
则报错;这种访问方式叫做深度优先
对于我们上面这个例子,由于找A 和 B 时都没有找到,则找到了D,因此打印了D.bar1,
新式类多继承例子
class D(object): #新式类
def bar1(self):
print "D.bar1"
class C(D):
def bar1(self):
print "C.bar1"
class B(D):
# def bar1(self):
# print "B.bar1"
pass #pass 代表什么也不做
class A(B,C):
# def bar1(self):
# print "A.bar1"
pass #pass 代表什么也不做
op = A() #实例化对象op
op.bar1() #访问op中bar1方法,但是具体访问到哪个方法呢???
执行结果如下
C.bar1 #为什么是C.bar1 ?? 和经典类结果相差很大...为什么?
分析如下:
新式类追寻的规律如下:
A --> B --> C --> D
意思是,首先找A,如果A中没有,则找B,如果B中没有,则找C,如果C中也没有,则找D,最后
都没找到,则报错;这种访问方式叫广度优先
对于我们上面的例子,由于A ,B 中都没有,则找C,C中找到了则打印C.bar1,
对于广度优先,你可以理解为找最近的点,比如上面的例子,A继承B,C ,由于在B中找不到,则
去找C,(因为A继承C,离A最近,)找到C,则直接打印C.bar1
三、多态
Pyhon不支持多态并且也用不到多态,这里简单带过,不做过多介绍
首先python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。
以下是维基百科中对鸭子类型得论述:
在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,
一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的
集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”
可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只
鸟就可以被称为鸭子。”
这里不做过多介绍
今晚就写到这里,之后的篇章中还会陆续介绍面向对象相关的内容