一、面向过程和面向对象
面向过程:程序里面有大量的函数,每一个环节都是进行函数的调用。编程思想是按照执行时从头到尾的顺序来进行编程的
面向对象:根据需求,划分不同的对象,将对象划分成若干个类,以对象的方式来进行方法或者行为
的调用,不是以函数为单位,而是以对象为单位。
举例说明:编写一个实现请假功能的代码块,大致流程为:员工请假—领导审批—人事记录
1、以面向过程的思想编程:
定义以下函数执行,伪代码如下:
def 请假(员工,领导)
pass
def 撤销请假流程(员工,领导)
pass
def 审批(员工,流程)
pass
def 记录(人事,员工)
pass
请假(员工,领导)
撤销请假流程(员工,领导)
审批(员工,流程)
记录(人事,员工)
2、以面向对象的思想编程:
分别定义员工 、领导、人事三个类。伪代码如下:
class worker:
def 请假(领导):
pass
def 撤销(领导)
pass
class leader:
def 审批(员工):
pass
def 驳回(员工):
pass
class hr:
def 记录(员工)
pass
w=Worker()
l=Leader()
hr=hr()
w.请假(m)
w.撤销(m)
l.审批(w)
hr.记录(w)
面向过程的缺点:
(1)只看方法,不能弄清楚方法里面具体做的事情,不清楚角色之间的关系
(2)定义方法时,程序员自己传入参数,所以会造成很多不合理的情况
(3)如果进行升级或者扩展,修改的代码太多。
3、总结:
面向过程:不是先分析是谁,先分析要怎么做,如武松打虎,就是编写函数【打(武松,老虎)】
面向对象:先分析是谁,然后再分析怎么做,如武松打虎,编写类以及类下方法【武松.打(老虎)】
面向对象的三个特征:封装、继承、多态
二、封装
信息的封装,主要为了方便调用者调用。
1. 成员的私有化
成员包括: 实例属性、实例方法、类属性、类方法、静态方法
经常对实例属性和实例方法进行封装(对成员进行私有化)
目的:只能在当前类中使用和访问,不能在类的外部直接访问。
具体的做法:如果希望一个属性或者一个方法是私有的,那么将名字 __(开头)** 注意不以两个__结尾
class computer:
def __init__(self):
self.cpu = "inter cpu"
self.__memory = "128G"
#__memory属于私有属性,可以在类的内部被使用,不能在类的外部被直接引用
def show(self):
print(self.cpu,self.__memory)
def get_memory(self):
return self.__memory
def set_memory(self,value):
self.__memory =value
c1 = computer()
print(c1.cpu)
c1.cpu = "AMD"
print(c1.cpu)
# print(c1.__memory) 'computer' object has no attribute '__memory'
c1.show()
print("================")
#如何在类的外部访问私有属性,在类的里面使用get(获取)和set(赋值)方法
print(c1.get_memory())
c1.set_memory("512G")
print(c1.get_memory())
输出:
inter cpu
AMD
AMD 128G
================
128G
512G
私有属性只能在类的内部进行访问,如果需要在外部访问和修改私有属性,需在类里面提供get(获取)和set(赋值)方法。
封装的优势:提高了代码的扩展性和可维护性。
需要注意的是,python中的封装是假封装,将__**名字伪装成_类名+私有成员的名字
如访问例子中的私有成员时,可以使用如下代码
print(c1._computer__memory)
同样得到输出:
512G
2. 使用property完成成员的私有化
目的:为了方便调用者调用,方法有如下两种:
(1)使用property函数
(2)使用property装饰器
a)property函数,在定义好get方法和set方法之后,将方法进行封装。
封装的时候按照顺序propery(获取,赋值,删除,注释),如果没有定义删除方法而定义了注释方法,
应该propery(获取,赋值,None,注释)
class computer:
def __init__(self):
self.__memory = "128G"
def get_memory(self):
return self.__memory
def set_memory(self,value):
self.__memory = value
def del_memory(self):
print("del方法执行")
del self.__memory
memory = property(get_memory,set_memory,del_memory,"computer内存")
c1 = computer()
print(c1.memory)
c1.memory = "256g"
print(c1.memory)
#del c1.memory
print(c1.memory)
help(computer.memory)
print(computer.memory.__doc__)
输出:
128G
256g
256g
Help on property:
computer内存
computer内存
b)使用property装饰器
class Computer:
def __init__(self):
self.__memory = "128G"
@property
def memory(self):
"computer描述"
return self.__memory
@memory.setter
def memory(self,value):
self.__memory =value
@memory.deleter
def memory(self):
print("del方法得到执行")
del self.__memory
c = Computer()
print(c.memory)
#print(c.a)
c.memory = "256G"
print(c.memory)
# del c.memory
# print(c.memory)
help(Computer.memory)
print(Computer.memory.__doc__)
输出为:
128G
256G
Help on property:
computer描述
computer描述
三、继承
1. 继承的关系
一般与特殊的关系
【特殊类】是【一般类】的子类
【一般类】是【特殊类】的父类
例子:水果 苹果 香蕉
子类可以继承父类,当继承父类后,就继承了父类下的所有成员(属性、方法)
作用跟定义在自己的类中一样。
2. 继承的实现
a)显式继承
格式如下:
class 类名(父类):
类体
具体实现如下所示:
class Fruit:
def show(self):
print("水果")
def __str__(self):
return "这是一个水果类"
class Apple(Fruit):
pass
f = Fruit()
f.show()
print("f=====>",f)
a = Apple()
a.show()
print("a=====>",a)
输出:
水果
f=====> 这是一个水果类
水果
a=====> 这是一个水果类
b)隐式继承
在python中,如果没有写明()继承,就叫隐式继承,只有一种情况,继承object父类
所有的类都会直接或者间接的继承object父类
3. 继承的意义
a)为什么要有子类继承父类
当父类有一些属性和方法,允许相关的子类使用的时候,子类可以通过继承的方式直接使用
如果子类有特殊的属性和方法,可以自行定义,甚至扩展,重写。
b)通过继承,实现代码的重用性,可以将公共的部分提取(抽取)出来, 放到父类中。
c)解决实际编程问题时:通过抽取对象得到类,通过抽取类得到父类
4. 两个重要的内建函数
a)isInstance(对象,类型):判断第一个参数指定的对象是否是第二个参数的类型(父类也可以)
例如:
class Fruit:
def show(self):
print("水果")
def __str__(self):
return "这是一个水果类"
class Apple(Fruit):
pass
f = Fruit()
a = Apple()
print(isinstance(a,Apple))
print(isinstance(a,Fruit))
输出:
True
True
b) issubclass(类型,类型):第一个参数是否是第二个参数的子类
class Fruit:
def show(self):
print("水果")
def __str__(self):
return "这是一个水果类"
class Apple(Fruit):
pass
f = Fruit()
a = Apple()
print(issubclass(Apple,Fruit))
print(issubclass(Apple,object))
输出:
True
True
5. 成员的继承
a)类属性、类方法、静态方法、实例方法的继承
关于方法的重写
子类继承了父类,如果父类的成员未必完全适合子类,可以是用重写的方式来自行扩展方法。
规则:如果子类中重写了父类的方法,运行时会按子类的方法进行执行,如果没有重写父类的方法,运行时按照父类的执行。
重写后调用父类成员:super().父类的成员 进行访问
class Bike:
#类属性
brand = "凤凰"
# 类属性
@classmethod
def copy_bike(cls):
print("仿照一台自行车")
#静态方法
@staticmethod
def static_method():
print("静态方法")
#实例方法
def bybike(self):
print("step1_双手扶把")
print("step2_骑上自行车")
print("step3_开始骑车")
class Cvbike(Bike):
def bybike(self):
print("step0_调整变速轮")
super().bybike()
b1 = Bike()
c1 =Cvbike()
print(Bike.brand)
b1.bybike()
b1.copy_bike()
b1.static_method()
print("============")
print(Cvbike.brand)
c1.bybike()
c1.copy_bike()
c1.static_method()
输出:
凤凰
step1_双手扶把
step2_骑上自行车
step3_开始骑车
仿照一台自行车
静态方法
============
凤凰
step0_调整变速轮
step1_双手扶把
step2_骑上自行车
step3_开始骑车
仿照一台自行车
静态方法
由上例可知,子类继承父类时可以继承类属性、类方法、静态方法、实例方法,可以在子类中重写方法并调用父类的方法。
b)实例属性的继承
1、如果子类中没有定义__init__方法,就会执行父类中的init方法,进行属性的初始化
2、如果子类中定义了自己的__init__方法,则会按子类中的属性进行初始化
3、如果子类的init中没有继承父类的__init__,pycharm会提示继承关系是否有问题。
4、子类的init方法继承了父类的__init__,尽量将父类的init放在第一行。
class Bike:
def __init__(self):
self.color = "蓝色"
class Cvbike(Bike):
def __init__(self):
super().__init__()
self.change = "变速器"
self.color = "白色"
b1 = Bike()
c1 =Cvbike()
print(b1.color)
print("==========")
print(c1.color)
print(c1.change)
输出:
蓝色
==========
白色
变速器
c) 私有成员的继承
子类不建议访问父类中的私有成员,如果一定要访问可以通过 _父类名+私有成员名
class C1:
def __p(self):
print("父类私有方法")
class D1(C1):
def t(self):
pass
c = C1()
d = D1()
c._C1__p()
输出:
父类私有方法
d)多重继承
一个子类可以继承多个父类,例如正方形是特殊的矩形,正方形也是特殊的菱形,那么正方形可以同时继承矩形和菱形
对于同名方法,哪一个父类写在前面,就先继承哪一个父类的方法。
如下:
class Rectangle:
def area(self):
print("求矩形面积")
class Diamond:
def area(self):
print("求菱形面积")
class Square(Rectangle,Diamond):
def s(self):
self.area()
s = Square()
s.s()
输出:
求矩形面积
对于多继承而言采用MRO原则: 方法调用顺序
如果是多继承,子类到每一个父类都是一条分支,按照继承的顺序,沿着每一条分支,从子类
到父类进行搜索,一直找到object类为止(深度优先)
如果非想继承指定父类方法
有两种方式:1、将指定的父类放在第一个位置
2、第二种,指定父类.方法
如下:
class Rectangle:
def area(self):
print("求矩形面积")
class Diamond:
def area(self):
print("求菱形面积")
class Square(Rectangle,Diamond):
def s(self):
Diamond.area(self)
s = Square()
s.s()
输出:
求菱形面积
三、多态
多态是指程序运行或者编译时期的多种形态
Python动态强类型语言,鸭子类型语言,多态上体现的不明显