9、Python面向对象
9-1、面向对象程序设计概述
1、什么是对象?
对象通俗来讲就是事物,我们可以把一个课程看成一个对象,也可以把一本书看成一个对象,还可以把一首歌看成一个对象;
对象可大可小,编程时,对象的划分标准根据项目管理者和程序开发者决定,主要目的是为了使项目的开发效率更高;
2、什么是面向对象?
我们生活的世界中,每一个复杂的事物都可以拆分为不同的部分构成;
其中的每个部分我们把它称之为对象;
比如:
我们要实现一个很大的项目,我们可以把这个项目拆分成各个不同的组成部分,然后分别对这些部分进行编程实现;
最终,再把各个部分组装成这个大项目;
这种做法能够从整体上来控制项目,让项目开发更有效率;
面向对象的程序设计提供了一种新的思维方式,软件设计的焦点不再是程序的逻辑流程,而是软件或程序中的对象以及对象之间的关系;
面向对象的特点:
第一个特定是易维护;因为程序被划分为各个不同的对象,代码可读性高,维护起来自然非常方便;
第二个特点是效率高;面向对象程序设计中,与我们自然界的思维方法非常相似,故可以大大提高开发效率;
第三个特点是质量高;采用面向对象很容易重用代码,可以重用以往经过测试的高质量类以实现新功能;
第四个特点是易扩展;面向对象的程序可以设计出高内聚、低耦合的系统,当系统功能需要扩展时,添加新的类和对象,再进行接口交互即可实现新功能;
Python支持面向过程、面向对象、函数式编程等多种编程范式;
Python不强制我们使用任何一种编程范式;
面向对象是一种方法学:
面向对象是一种描述业务问题、设计业务实体和实体之间关系的方法;
面向对象主要用于软件开发的分析和设计阶段,通常使用UML(统一建模语言)进行建模;
UML并不是软件设计开发的方法,而是一种描述软件开发过程的图形化标记;UML使用若干种模型来描述软件开发中的每个步骤;
(1)用例图
用例图描述系统使用者与系统之间的交互关系,用例图通常用于系统的分析阶段,分析系统中的主要流程;
(2)活动图
是对用例图的补充,用于分析复杂的用例,表示用例中的逻辑行为;
活动图类似于传统的数据流程图,可以描述业务的流程,帮助分析人员确定用例中交互及其关系;
(3)状态图
用于对系统的行为进行建模,用于分析和设计阶段之间的过渡时期;
状态图和活动图有些相似,但状态图是对单个对象的描述,强调对象内部状态的变迁过程;
(4)类图
类图包括属性、操作以及访问权限等内容;
类图用于系统设计阶段,根据系统用例提炼出系统中的对象;
类图是面向对象设计的核心,通过类图可以表示抽象、继承、多态等面向对象特性,
能够表现系统的架构设计及系统中对象之间的层次关系;
(5)序列图和协助图
都可以用于描述系统中对象之家的行为,是对系统具体行为的设计;通常用于类图设计完成后的一个步骤;
序列图是对用例的具体实现,通过消息的方式描述系统中对象的生命周期和控制流程;
而协助图侧重于对消息的建模,描述系统对象之间的交互关系;
(6)组件图和部署图
组件图用于描述系统组件之间的交互,类和组件之间的依赖关系;
部署图用于描述系统的部署及组件之间的配置;
这些图形标记都可以使用UML建模工具绘制,例如visio
9-2、python的类
1、什么是类?
类是某些对象之间的共性抽象,隐藏了对象内部复制的结构和实现,类通俗的讲就是很多相同事物的综合;
总之一句话:类是对象的抽象,对象是类的具体表现形式,也叫类的实例;
类由变量和函数两部分组成,类中的变量称为成员变量,类中的函数称为成员函数;
类和对象是面向对象中的两个重要概念;
2、python中类和对象的定义:
类名的首字符一般大写;
当程序员需要创建的类型不能用简单类型来表示时,则需要定义类,然后利用定义的类创建对象;
类把需要使用的变量和方法组合在一起,这种方式称为封装;
3、对象的创建:
创建对象的过程称为实例化;
当一个对象被创建后,包含3个方面的特性:对象的句柄、属性和方法;
对象的句柄用于区分不同的对象,当对象被创建后,该对象获取一块存储空间,存储空间的地址即为对象的标识;
对象的属性和方法与类的成员变量和成员函数相对应;
4、类的属性:
类由属性和方法组成,类的属性是对数据的封装,而类的方法则表示对象具有的行为;
类的属性:
类的属性一般分为私有属性和公有属性;
Python中使用约定属性名称来达到数据封装的目的,如果属性的名字以两个下划线开始,就表示为私有属性,否则默认为公有属性;
类的方法也同样使用这样的约定;
Python的属性分为实例属性和静态属性;
实例属性是以self作为前缀的属性;
如Python类的构造方法init(),如果init()方法中定义的变量没有使用self作为前缀声明,则该变量只是普通的局部变量;
例:
class Fruit:
price = 0 # 类属性
def __init__():
self.color = "red" # 实例属性
self.size = "small" # 私有变量
zone = "China" # 局部变量
类的外部不能直接访问私有属性;
但Python提供了直接访问私有属性的方法,可用于程序的测试和调试;
私有属性的访问格式如下所示:
instance._classname__attribute
instance表示实例化对象,classname表示类名,attribute表示私有属性;
但是这种直接暴露数据的做法是不提倡的,因为随意改变实例属性的值,可能会导致程序数据安全方面的问题;
这种访问方式主要用于开发阶段的测试或调试时使用;
实际一般的做法是定义相关的get方法获取实例属性的值;
类提供了一些内置属性,用于管理类的内部关系,如:dict、bases、doc等;
#coding:utf-8
#类的内置属性
class Fruit:
def __init__(self):
self.__color='red'
class Apple(Fruit):
'''This is doc'''
pass
if __name__=="__main__":
fruit=Fruit()
apple=Apple()
print Apple.__bases__ #输出基类组成的元组
print apple.__dict__ #输出属性组成的字典
print apple.__module__ #输出类所在的模块名
print apple.__doc__ #输出doc文档
python中属性的实现和修改:
#coding:utf-8
#python中方法及属性的实现
class man: #类man
pass
li=man() #类的对象/实例
print li.__dict__ #可以使用__dict__查看对象li的属性
li.interest="runing" #为li这个实例添加爱好这个属性,再输出
print li.__dict__
wang=man()
print wang.__dict__ #从结果看,wang这个实例的属性不受li对象属性的影响
print li.__class__.__dict__ #查看一个实例所属的类的的属性的格式
li.__class__.toufa="red" #为li对象所在的类添加toufa属性
print li.__class__.__dict__
print wang.__class__.__dict__ #发现wang的类属性也会随之改变
#从上面可以看出,如果是修改某个实例的属性,则其它实例的属性不会受影响;
#但是,如果是修改对象所在类的属性时,则该类中所有的对象的类属性均会改变。
5、类的方法:
类的方法也分为公有方法和私有方法,私有方法不能直接被模块外的类或方法调用,也不能被外部的类或函数调用;
Python使用staticmethod()或@staticmethod()修饰器把普通的函数转化为静态方法;
Python的静态方法并没有和类的实例进行名称绑定,要调用只需要使用类名作为它的前缀即可;
#coding:utf-8
#类的方法
class Fruit:
price=0 #类变量
def __init__(self): #定义私有变量
self.__color='red'
def getColor(self):
print self.__color #打印私有变量
@staticmethod #使用@staticmethod声明getprice为静态方法
def getPrice():
print Fruit.price
def __getPrice(): #定义私有函数
Fruit.price=Fruit.price+10
print Fruit.price
count=staticmethod(__getPrice) #使用staticmethod把__getPrice()转化为静态方法
if __name__=="main":
apple=Fruit() #实例化apple类
apple.getColor() #使用实例调用静态方法
Fruit.count() #使用类名调用静态方法
banana=Fruit()
Fruit.getPrice()
Fruit.count()
python中方法的定义和使用:
注意:如果不想让类中的某个方法被外部对象调用,可以使用方法隐藏,即在想要隐藏的方法前面加上两个下划线,
隐藏属性同理,具体如下:
6、类中内置方法:
Python中定义了一些专用的方法,这些专用的方法丰富了程序的设计功能,用于不同的应用场合;
init( )和del( )就是类的内置方法,分别表示初始化对象(在创建新对象时调用)和释放对象(在对象被删除之前调用):
#coding:utf-8
#类中常见的一些方法
#1.__init__()构造函数:建立
class people:
def hi(self):
print 8899
def __init__(self):
a="how are you?"
b="__fine,thank you"
print a+b
people()
print"\n"
#2.__del__()析构函数:释放
class friend:
def hi(self):
print 8899
def __init__(self):
print "我是init最先调用"
def __del__(self):
a="我是析构函数"
b="——对象生命周期结束,现在我得删除对象善后了!"
print a+b
xiaoli=friend() #对象xiaoli是具体的,是局部实例
xiaoli.hi()
friend() #直接用类名是全局实例,会调用析构函数
7、垃圾回收机制
Java中并没有提供析构函数,而是采用垃圾回收机制清理不再使用的对象;
Python中也采用垃圾回收机制清除对象,Python提供类gc模块释放不再使用的对象;
垃圾回收机制有多种算法,Python采用的是引用计数的方式,当某个对象在其作用域内引用计数为0时,Python就会自动清除该对象;
垃圾回收机制很好的避免了内存泄漏的发生;
函数collect()可以一次性收集所有待处理的对象;
#coding:utf-8
#Python垃圾回收机制
import gc
class Fruit:
def __init__(self,name,color): #在__init__方法中定义两个属性,水果的名称和颜色
self.__name=name
self.__color=color
def getColor(self):
return self.__color
def setColor(self,color):
self.__color=color
def getName(self):
return self.__name
def setName(self,color):
self.__name=name
class FruitShop:
def __init__(self):
self.fruits=[] #为FruitShop类定义属性fruits,是一个列表,用于存放水果店中的水果
def addFruit(self,fruit): #定义addFruit方法,把对象fruit添加到fruits列表中
fruit.parent=self
self.fruits.append(fruit)
if __name__=="__main__":
shop=FruitShop()
shop.addFruit(Fruit("apple","red")) #向shop中添加两个fruit对象
shop.addFruit(Fruit("banala","yellow"))
print gc.get_referrers(shop) #调用get_referrers()列出shop对象关联的所有对象
del shop #删除shop对象,但是shop对象关联的其他对象并没有释放
print gc.collect() #调用collect()释放shop对象关联的其他对象,collect()返回结果表示释放的对象个数
8、方法的动态特性:
Python作为动态脚本语言,编写的程序具有很强的动态性,可以动态添加类的方法,把某个已经定义的函数添加到类中;
添加新方法的语法格式如下:
class_name.method_name = function_name
其中class_name表示类名,method_name表示想添加的新的方法的名称,
function_name表示一个已经存在的外部函数add( ),函数的内容即为想添加的新的方法的内容;
#coding:utf-8
#方法的动态性
class Fruit:
pass
def add(self): #定义在类外的函数add()
print 'price is 100'
if __name__ == "__main__":
Fruit.sale=add #动态添加price函数,其在Fruit类中的新名字为sale
fruit=Fruit() #类的初始化
fruit.sale() #利用对象调用新加入的方法
利用Python的动态特性,还可以对已经定义的方法进行修改,修改的语法格式如下:
class_name.method_name=function_name
其中class_name表示类名,method_name表示需要更新的类中的方法的名称,
function_name表示一个已经存在的外部函数update( ),函数的内容即为原方法被更新后的内容;
#coding:utf-8
#方法的动态性:动态更新已有方法
class Fruit:
def grow(self):
print 'grow in yunnan'
def update(self): #定义在类外的函数update()
print 'grow in hubei'
if __name__ == "__main__":
fruit=Fruit() #类的初始化
fruit.grow() #利用对象调用原来的方法
Fruit.grow=update #动态更新原有函数
fruit.grow() #利用对象调用更新后的方法
9、属性和方法的区别:
在面向对象中,方法和属性这两个概念很容易混淆;
以人这个对象为例:
人这个对象可以有吃饭的方法,睡觉的方法等;
而人这个对象有头这个属性,手这个属性,脚这个属性;
总结一句话就是:属性代表对象的数据,而方法代表对象的操作;
10、内部类:
Python和Java一样,可以在类的内部定义类;
例如:汽车由门、车轮等部件组成,可以设计出汽车、门、车轮等3个类;
而门、车轮是汽车的一部分,因此把门、车轮表示的类放在汽车的内部;
这种在某个类内部定义的类称为内部类;
内部类的调用方法有两种:
第一种是直接使用外部类调用内部类,生成内部类的实例,再调用内部类的方法:
object_name = outclass_name . inclass_name( )
object_name . method( )
第二种是先对外部类进行实例化,然后再实例化内部类,最后调用内部类的方法:
out_name = outclass_name( )
in_name = out_name . inclass_name( )
in_name . method( )
例子 :
#coding:utf-8
#内部类的两种调用方法:
class Car:
class Door:
def open(self):
print 'open the door'
class Wheel:
def run(self):
print 'start to run'
if __name__=="main":
#调用方式一:直接使用外部类调用内部类,生成内部类的实例,再调用内部类的方法
doors=Car.Door()
doors.open()
#调用方式二:先对外部类进行实例化,然后再实例化内部类,最后调用内部类的方法
car=Car()
wheels=car.Wheel()
wheels.run()