六、面向对象
(一)面向过程
定义:分析解决问题的步骤,然后逐步实现
公式:程序=算法+数据结构
(二)基本内容
1.定义
找出解决问题的人,然后分配职责
2.公式
程序=对象+交互
3.思想 识别对象,找人 分配职责,干活 建立交互,调用
class computer:
#数据成员
def __init__(self,brand_name,cpu_model,color):
#self 是调用当前方法的对象地址
self.brand_name = brand_name
self.cpu_model = cpu_model
self.color = color
#方法成员
def print_information(self):
"""
打印产品信息
:return:
"""
print("电脑品牌是{},颜色是:{},cpu型号是 {},".format(self.brand_name,self.color,self.cpu_model))
def open_computer(self):
"""
启动电脑
:return:
"""
print("正在开机")
#创建对象,实际在调用__init__方法
com01 = computer("戴尔","黑色","inter_ci5")
com01.print_information()
com01.open_computer()
com01 = computer("联想","黑色","inter_ci511")
com01.print_information()
com01.open_computer()
(三)具体内容
-
类 class -
定义:一个抽象的概念,如动物、人类
格式:类名所有单词首字母大写
——init—— 构造函数,创建对象时被调用
组成:
数据 (数据不同,类可能相同)
方法(方法不通,则类不同)
-
对象
定义 类的实体
-
实例变量与实例方法
"""
实例变量
调用 print(对象.<变量>)
对象.<变量> = #修改
实例方法
def <>(self,参数列表):
方法体
调用:对象.<>
作用:操作实例的数据
"""
class Person: #类
def __init__(self,name,age): #数据成员
self.name = name
self.age = age
def eat(self): #方法
print("{}吃了饭".format(self.name))
name = "刘亦菲"
age = 32
peo = Person(name,age) #对象 具体的事物
peo.age = 31 #修改
peo.eat()
注:
对象:类的具体事例,即归属于某个类别的个体,(具体的事物)
类是创建对象的模板。
--数据成员(变量):名词类型的状态。
--方法成员(函数):动词类型的行为
-
类变量与类方法
含义:
类变量 描述所有对象的共有数据
类方法 用于操作类变量
语法
"""
定义:
class <>: #在类中,方法外定义变量
变量名 = 表达式 #数据
@classmethod
def <>(cls,参数列表): #方法
方法体
调用:
类名.变量名
类名.<方法名>
"""
class Beauty:
count =0 #类变量,统计人数
def __init__(self,name,age):
self.name = name
self.age = age
Beauty.count += 1 #类变量必须用类调用
@classmethod
def print_count(cls):
print("共有%d个人"%Beauty.count)
beauty1 = Beauty("刘亦菲",32)
beauty2 =Beauty("貂蝉",19)
Beauty.print_count() #2人
-
静态方法
既不操作类变量,也不操作实例变量,将函数引入类中,就不需要加self
""" 语法 定义 @staticmethod def <>(): 方法体 调用 类名.方法名() """ #二维向量 lists = [ ["00","01","02","03"], ["10","11","12","13"], ["20","21","22","23"], ["30","31","32","33"], ] class Vector: "坐标" def __init__(self,x,y): self.x = x self.y = y @staticmethod #静态方法 def up(self):#上移 return (-1,0) def down(self):#下移 return (1,0) def right(self):#上移 return (0,1) def left(self):#上移 return (0,-1) class VectorHelper: def __init__(self,lists): self.lists = lists def get_elements(self,place,vect_dice,count): """ place 位置坐标 vect_dice 位移方向 count 距离 """ list_temp = [] for i in range(count): place.x += vect_dice.x place.y += vect_dice.y list_temp.append(self.lists[place.x][place.y]) print(list_temp) helper = VectorHelper(lists) helper.get_elements(Vector(0,2),Vector.down,2)
(四)特性
1.封装
(1)定义
从数据角度讲,将基本数据复合成一个自定义类型 从行为讲,向类外提供必要的功能,隐藏实现的细节 从设计角度,分而治之,变则疏之(变化点独立封装),高内聚(单任务),低耦合
(2)私有成员
作用:无需向类外提供的成员,可以通过私有化进行屏蔽 方法:命名使用双下划线开头(数据和方法都可用) 本质 用将变量名<> 改为_类名__<> 来混淆
#封装的过度版1
class Person:
def __init__(self,name,age):
self.name = name
self.__age = age
def show_age(self):
return self.__age
def update_age(self,age):
if 0<=age<=100:
self.age = age
else:
raise ValueError("age的范围不对")
w01 = Person("")
w01.age =100 #则无法进行修改,因为属性 已隐藏
w01._Wife__age = 100 #需使用此格式来修改
<变量>.__dict__() 可以以字典的形式查看
(3)属性@property
使用私有成员方法封装
只写或只读 <变量> = property(None,<写>) <变量> = property(<读>,None)
"""
过度版2
语法:使用property(<读取方法>,<写入方法>)
"""
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
age = property(__show_age,__updata_age) #property属性,负责拦截读写操作
#property(None,updata_age) 只能写
#property(None,updata_age) 只能读
def __show_age(self):
return self.__age
def __update_age(self,age):
if 0<=age<=100:
self.__age = age
else:
raise ValueError("age的范围不对")
w01 = Person("刘亦菲",32)
w01.age = 33
终极版
"""
定义
@property #只负责拦截读
def <name>(self):
return self.__name
@name.setter #只负责拦截写入操作
def <name>(self.name):
self.__name = name
调用
对象.属性 = 数据
变量 = 队形.属性名
"""
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
@property
def age(self):
return self.__age
@age.setter
def age(self,age):
if 0<=age<=100:
self.__age = age
else:
raise ValueError("age的范围不对")
w01 = Person("刘亦菲",32)
w01.age = 33
2.继承
(1)性质
子类之间可以相互调用,子类也可以调用父类成员,父类对象只可以调用父类成员
多个子类在概念上一致的,所以就抽象出一个父类;
多个子类的共性,可以提取到父类中,
在实际开发中:
从设计角度:先有子,再有父
从编码角度:先有父,再有子
价值-----父类隔离子类的变化,规范子类
(2)组成
变量:
子类若没有构造函数,则使用父类的构造函数(init); 子类若具有构造函数,则必须先调用父类
子类通过super(). __ init __()调用父类参数
子类可以调用父类的方法
方法-----子类可以调用父类的方法
class Person:
def __init__(self.name):
self.name = name
class Student(Person):
def __init__(self,name,score):
super().__init__(name)
self.score = score
per = Person()
stu = Student()
#判断对象是否属于一个类型
print(isinstance(per,Person)) #True
#判断一个类型是否属于另一个类
print(issubclass(Student,Person)) #True
3.多态
定义 父类的同一种动作或者行为,在不同的子类有不同的实现 调用父,执行子
4.设计原则
开-闭原则(目标)
对扩展开放,对修改关闭
增加新功能,不改变原有代码
类的单一职责(类的定义) 依赖倒置(依赖抽象)
客户端代码(调用的类,使用者)尽量(使用)抽象的组件(做一个父类-继承)。抽象的是稳定;实现是多变
组合复用原则 复用的最佳实践 里氏替代- 迪米特法则
#图形管理器
class GraphicalManager:
def __init__(self):
self.__graph_list = []
def insert_graph(self,graph):
if isinstance(graph,Graphical): #判断对象graph是否属于Graphical类
self.__graph_list.append(graph)
else:
raise ValueError()
def sum_area(self): #计算所有图形的面积和
result = 0
for item in self.__graph_list:
result += item.calcu_area()
return result
class Graphical: #图形
#父类太过于抽象,无法写出方法体
def calcu_area(self):
#若子类不重写,则报错
raise NotImplementedError()
class Square(Graphical):
def __init__(self,length,wide):
self.length = length
self.wide = wide
def calcu_area(self):
return self.length * self.wide
squ=Square(4,5)
manager = GraphicalManager()
manager.insert_graph(squ)
print(manager.sum_area)
5.类与类的关系
泛化(继承) b类继承a类 关联(组合) a类中包含B类成员 作用域整个类 依赖 b类作为a类中方法的参数 作用域一个方法
#员工管理器
class StaffManager:
def __init__(self):
self.__staff_lists=[] #员工列表
def insert(self,staff): #将员工添加到列表
if isinstance(staff,Staff):
self.__staff_lists.append(staff)
else:
raise ValueError()
def sum_salary(self): #计算员工工资和
result = 0
for item in self.__staff_lists:
result += item.calcu_salary()
return result
#员工
class Staff:
def __init__(self,salary): #员工基础工资
self.salary = salary
def calcu_salary(self):
raise NotImplementedError()
class Programmer(Staff):
def __init__(self,salary,project_salary):#基础工资+项目分红
super(). __ init __(salary)
self.project_salary=project_salary
def calcu_salary(self):
return self.salary+ self.project_salary
6.常见内置函数
isinstance(<对象>,类) 判断对象是否是一个类型,返回true,flase issubclass((<类>,父类) 判断一个类型是否属于另一个类型 type() 可以判断类型 内置可重写函数 以双下划线开头,双下划线结尾 __ str __ ()函数 将对象转化为字符串(对人友好) __ repr __ () 将对象转化为字符串(解释器可识别)
class Stu:
def __init__(self,name,sex):
self.name = name
self.sex = sex
def __str__(self):#任意格式
return "{}{}".format(name,sex)
def __repr_(self): #有固定的格式
return "Stu({},{})".format(name,sex)
stu = Stu("林妹妹","女")
print(stu)
stu1 = repr(stu) #克隆对象
eval(stu1) # stu对象 Stu("林妹妹","女")
7.运算符重载
(1)定义
让自定义生成的对象能够使用运算符
(2) 类型
算数运载符重载------格式:对象 +数字
反向算数运载符重载 ------格式:对象 +数字
class Vector:
def __init__(self,x):
self.x = x
def __add__(self, other): #算数运载符重载
return Vector(self.x+other)
def __sub__(self, other):
return Vector(self.x - other)
def __mul__(self, other):
return Vector(self.x * other)
def __radd__(self, other): #反向算数运载符
return Vector(other+self.x)
复合运载符重载
比较运载符重载