面向对象文档
-
分析出解决问题的步骤,然后逐步实现。
例如:婚礼筹办
-- 发请柬(选照片、措词、制作)
-- 宴席(场地、找厨师、准备桌椅餐具、计划菜品、购买食材)
-- 婚礼仪式(定婚礼仪式流程、请主持人)
-
公式:程序 = 算法 + 数据结构
-
优点:所有环节、细节自己掌控。
-
缺点:考虑所有细节,工作量大。
-
面向对象
-
找出解决问题的人,然后分配职责。
例如:婚礼筹办
-- 发请柬:找摄影公司(拍照片、制作请柬)
-- 宴席:找酒店(告诉对方标准、数量、挑选菜品)
-- 婚礼仪式:找婚庆公司(对方提供司仪、制定流程、提供设备、帮助执行)
-
公式:程序 = 对象 + 交互
-
优点
-
思想层面:
-- 可模拟现实情景,更接近于人类思维。
-- 有利于梳理归纳、分析解决问题。
-
技术层面:
-- 高复用:对重复的代码进行封装,提高开发效率。
-- 高扩展:增加新的功能,不修改以前的代码。
-- 高维护:代码可读性好,逻辑清晰,结构规整。
-
缺点:学习曲线陡峭。
-
类和对象
-
类:一个抽象的概念,即生活中的”类别”。
-
对象:类的具体实例,即归属于某个类别的”个体”。
-
类是创建对象的”模板”。
-- 数据成员:名词类型的状态。
-- 方法成员:动词类型的行为。
-
类与类行为不同,对象与对象数据不同。
-
语法
Self 指向的是对象地址, .是包含的
-
定义类
-
代码
class 类名:
“””文档说明”””
def _init_(self,参数列表):
self.实例变量 = 参数
方法成员
-
说明
-- 类名所有单词首字母大写.
-- _init_ 也叫构造函数,创建对象时被调用,也可以省略。
-- self 变量绑定的是被创建的对象,名称可以随意。
-
创建对象(实例化)
变量 = 构造函数 (参数列表)
-
实例成员
-
实例变量
-
语法
-
定义:对象.变量名
-
调用:对象.变量名
-
说明
-
首次通过对象赋值为创建,再次赋值为修改.
w01 = Wife()
w01.name = “丽丽”
w01.name = “莉莉”
-
通常在构造函数(_init_)中创建。
w01 = Wife(“丽丽”,24)
print(w01.name)
-
每个对象存储一份,通过对象地址访问。
-
作用:描述某个对象的数据。
-
__dict__:对象的属性,用于存储自身实例变量的字典。
-
实例方法
-
语法
(1) 定义: def 方法名称(self, 参数列表):
方法体
(2) 调用: 对象地址.实例方法名(参数列表)
不建议通过类名访问实例方法
-
说明
(1) 至少有一个形参,第一个参数绑定调用这个方法的对象,一般命名为"self"。
(2) 无论创建多少对象,方法只有一份,并且被所有对象共享。
-
作用:表示对象行为。
-
类成员
-
类变量
-
语法
-
定义:在类中,方法外定义变量。
class 类名:
变量名 = 表达式
-
调用:类名.变量名
不建议通过对象访问类变量
-
说明
(1) 存储在类中。
(2) 只有一份,被所有对象共享。
-
作用:描述所有对象的共有数据。
-
类方法
-
语法
-
定义:
@classmethod
def 方法名称(cls,参数列表):
方法体
-
调用:类名.方法名(参数列表)
不建议通过对象访问类方法
-
说明
(1) 至少有一个形参,第一个形参用于绑定类,一般命名为'cls'
(2) 使用@classmethod修饰的目的是调用类方法时可以隐式传递类。
(3) 类方法中不能访问实例成员,实例方法中可以访问类成员。
-
作用:操作类变量。
-
静态方法
-
语法
-
定义:
@staticmethod
def 方法名称(参数列表):
方法体
-
调用:类名.方法名(参数列表)
不建议通过对象访问静态方法
-
说明
(1) 使用@ staticmethod修饰的目的是该方法不需要隐式传参数。
(2) 静态方法不能访问实例成员和类成员
-
作用:定义常用的工具函数。
-
三大特征
-
封装
-
数据角度讲
-
定义:
将一些基本数据类型复合成一个自定义类型。
-
优势:
将数据与对数据的操作相关联。
代码可读性更高(类是对象的模板)。
-
行为角度讲
-
定义:
类外提供必要的功能,隐藏实现的细节。
-
优势:
简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
-
私有成员:
-
作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
-
做法:命名使用双下划线开头。
-
本质:障眼法,实际也可以访问。
私有成员的名称被修改为:_类名__成员名,可以通过_dict_属性或dir函数查看。
-
属性@property:
公开的实例变量,缺少逻辑验证。私有的实例变量与两个公开的方法相结合,又使调用者的操作略显复杂。而属性可以将两个方法的使用方式像操作变量一样方便。
-
定义:
@property
def 属性名(self):
return self.__属性名
@属性名.setter
def 属性名(self, value):
self.__属性名= value
-
调用:
对象.属性名 = 数据
变量 = 对象.属性名
-
说明:
通常两个公开的属性,保护一个私有的变量。
@property 负责读取,@属性名.setter 负责写入
只写:属性名= property(None, 写入方法名)
class Wife: def __init__(self, name=None, weight=None): self.name= name self.weight=weight def print_weight(self): if self.weight>50: print('你猜') else: print(self.weight) def __fun01(self): print('我不想说的事情') w01 = Wife('芳芳',40) # w01 = Wife('芳芳',80) # w01.print_weight() # w01.__fun01() #不能调用私有成员 print(w01.__dict__) #显示所有实例变量信息 ''' 隐藏数据,限制 ''' class Wife: def __init__(self, name=None, weight=None): self.name = name # self.__weight=weight #被方法隐藏 self.set_weight(weight) self.__weight # 写入方法 def set_weight(self, value): if 20 <= value <= 200: self.__weight = value # 隐藏在这个里 # {'name': '芳芳', '_Wife__weight': 40, 'weight': 900} else: raise Exception('我不要') # 读取方法 def get_weight(self): return self.__weight w01 = Wife('芳芳', 40) # w01.__fun01() #不能调用私有成员 # w01.weight = 900 # print(w01.weight) # 通过方法修改数据 # w01.set_weight(50) # 通过方法获取数据 print(w01.get_weight()) # print(w01._Wife__weight()) print(w01.__dict__) # 显示所有实例变量信息 """ 隐藏数据 通过方法隐藏数据 """ class Wife: def __init__(self, name="", weight=0): self.name = name # 如果不隐藏数据,外部可以任意操作. # self.weight = weight self.set_weight(weight) # 写入方法 def set_weight(self,value): if 20 <= value <=200: self.__weight = value else: raise Exception("我不要") # 读取方法 def get_weight(self): return self.__weight w01 = Wife("芳芳", 40) # w01.weight # w01.__weight # 通过方法修改数据 w01.set_weight(45) # 通过方法获取数据 print(w01.get_weight()) print(w01.__dict__) """ 隐藏数据 通过property隐藏数据property价值:将对实例的变量操作拦截下来(拦截)执行读和写 """ class Wife: def __init__(self, name="", weight1=0): self.name = name # 如果不隐藏数据,外部可以任意操作. self.weight = weight1 #给了双下划线weight # self.set_weight(weight) #为了更直观数据,不用通过方法隐藏数据 # 写入方法 def set_weight(self,value): if 20 <= value <=200: self.__weight = value else: raise Exception("我不要") # 读取方法 def get_weight(self): return self.__weight # 类内方法外,类变量和实例变量一样,被类变量覆盖了实例变量; # 1创建类变量,覆盖实例变量,名称相同 # weight= property(读取方法,写入方法) # 2创建property对象property(读取方法,写入方法)这个地方只是获取方法执行,而不是返回值 weight1= property(get_weight,set_weight) #*只是获取方法,而不是要返回值 w01 = Wife("芳芳", 40) # w01.weight # w01.__weight # 通过方法修改数据 # w01.set_weight(45) # 通过方法获取数据 # print(w01.get_weight()) # 3.通过类变量直接修改数据 w01.weight=45 print(w01.weight) print(w01.__dict__) """ 隐藏数据 通过property隐藏数据property价值:将对实例的变量操作拦截下来(拦截)执行读和写 """ 隐藏数据 -- 通过property 步骤: 1. 在__init__方法中定义实例变量 2. 使用@property修饰对象实例变量的读取方法 注意:方法名与实例变量名相同 方法体返回私有变量 3. 使用 @读取方法名.setter 修饰写入方法. 注意:方法名与写入方法和实例变量名相同 方法体修改私有变量 练习:exercise02py """ """ class Wife: def __init__(self, name="", weight1=0): self.name = name # 如果不隐藏数据,外部可以任意操作. self.weight = weight1 #给了双下划线weight # self.set_weight(weight) #为了更直观数据,不用通过方法隐藏数据 # 创建p对象,绑定读取方法 @property #weight=property(weight,none) # 读取方法 def weight2(self): return self.__weight @weight2.setter #读取方法名 # 写入方法''' 练习:创建技能类(技能名称,冷却时间,攻击力度,消耗法力) ''' class Attack: total_power=2000 def __init__(self, name=None, attack=None, time=None, power=None): self.name = name self.attack = attack self.time=time self.power=power @property def name(self): return self.__name @name.setter def name(self,value): self.__name=value @property def time(self): return self.__time @time.setter def time(self,value): if 0 <= value <=120: self.__time = value else: raise Exception("我不要") @property def attack(self): return self.__attack @attack.setter def attack(self,value): if 0 <= value <= 200: self.__attack = value else: raise Exception("我不要") @property def power(self): return self.__power @power.setter def power(self,value): if -100 <= value <= 100: self.__power = value # Attack.total_power-=value else: raise Exception("我不要") def attack01(self): Attack.total_power-=self.attack print(self.name,self.time,self.attack,self.power,Attack.total_power) w01=Attack('火影',40,80,50) w01.time=80 print(w01.__dict__) w01.attack01() print(Attack.total_power) # s01=Attack('九阳神功',110,90,76) # print(s01.__dict__) # print(Attack.total_power) # s01.attack01() def weight6(self,value): if 20 <= value <=200: self.__weight = value else: raise Exception("我不要") # 类内方法外,类变量和实例变量一样,被类变量覆盖了实例变量; # 1创建类变量,覆盖实例变量,名称相同 # weight= property(读取方法,写入方法) # 2创建property对象property(读取方法,写入方法)这个地方只是获取方法执行,而不是返回值 # weight= property(get_weight,set_weight) #*只是获取方法,而不是要返回值 w01 = Wife("芳芳", 40) # w01.weight # w01.__weight # 通过方法修改数据 # w01.set_weight(45) # 通过方法获取数据 # print(w01.get_weight()) # 3.通过类变量直接修改数据 w01.weight=61 print(w01.weight) print(w01.__dict__) print(w01.__dir__()) class Wife01: def __init__(self, name="", weight=0): self.name = name # 如果不隐藏数据,外部可以任意操作. # self.weight = weight #给了双下划线weight # self.set_weight(weight) #为了更直观数据,不用通过方法隐藏数据 self.__weight=weight #只能读不能写 # 创建p对象,绑定读取方法 # @property #weight=property(weight,none) # # 读取方法 # def weight(self): # # if 条件 # return self.__weight #*10 # @weight.setter #调动读取方法名 # 写入方法 #只能读的属性 def weight(self,value): if 20 <= value <=200: self.__weight = value else: raise Exception("我不要") weight= property(None,weight) w01=Wife01("小华",49) w01.weight=30 print(w01.__dict__) ''' 定义敌人类 通过方法隐藏数据 ''' class Attack: def __init__(self, name=None, attack=None): self.name = name # self.__weight=weight #被方法隐藏 self.set_attack(attack) #*重点在这个里 # 写入方法 def set_attack(self, value): if 0 <= va''' 张无忌教赵敏九阳神功 赵敏教张无忌玉女心经 张无忌工作赚了5000元 赵敏工作赚了10000元 打印出每个人的技能和存款 ''' class Person: def __init__(self, name=None): self.name=name self.money=0 self.skills=[] def teach(self,other,skill): other.skills.append(skill) def work(self,value): self.money+=value zwj=Person('张无忌') # w01.skill="九阳神功" zm=Person('赵敏') zwj.teach(zm,'九养生功') lue <= 100: self.__attack = value # 隐藏在这个里 # {'name': '芳芳', '_Wife__weight': 40, 'weight': 900} else: raise Exception('我不要') # 读取方法 def get_attack(self): return self.__attack w01 = Attack('芳芳', 60) # w01.set_attack(120) # w01.__fun01() #不能调用私有成员 # w01.weight = 900 # print(w01.weight) # 通过方法修改数据 # w01.set_weight(50) # 通过方法获取数据 print(w01.get_attack()) # print(w01._Attack__attack()) print(w01.__dict__) # 显示所有实例变量信息 ''' 定义敌人类 通过property隐藏数据 ''' class Attack: def __init__(self, name=None, attack1=None): self.name = name self.attack = attack1 # 被方法隐藏 # self.set_attack(attack) #*重点在这个里 @property # weight=property(weight,none) # 读取方法 def get_attack(self): return self.__attack @get_attack.setter # 写入方法 def set_attack(self, value): if 0 <= value <= 100: self.__attack = value # 隐藏在这个里 # {'name': '芳芳', '_Wife__weight': 40, 'weight': 900} else: raise Exception('我不要') # weight1 = property(get_attack, set_attack) w01 = Attack('芳芳', 60) w01.attack = 86 # w01.set_attack(120) # w01.__fun01() #不能调用私有成员 # w01.weight = 900 # print(w01.weight) # 通过方法修改数据 # w01.set_weight(50) # 通过方法获取数据 print(w01.attack) # print(w01._Attack__attack()) print(w01.__dict__) # 显示所有实例变量信息 ''' 练习:创建技能类(技能名称,冷却时间,攻击力度,消耗法力) ''' class Attack: total_power=2000 def __init__(self, name=None, attack=None, time=None, power=None): self.name = name self.attack = attack self.time=time self.power=power @property def name(self): return self.__name @name.setter def name(self,value): self.__name=value @property def time(self): return self.__time @time.setter def time(self,value): if 0 <= value <=120: self.__time = value else: raise Exception("我不要") @property def attack(self): return self.__attack @attack.setter def attack(self,value): if 0 <= value <= 200: self.__attack = value else: raise Exception("我不要") @property def power(self): return self.__power @power.setter def power(self,value): if -100 <= value <= 100: self.__power = value # Attack.total_power-=value else: raise Exception("我不要") def attack01(self): Attack.total_power-=self.attack print(self.name,self.time,self.attack,self.power,Attack.total_power) w01=Attack('火影',40,80,50) w01.time=80 print(w01.__dict__) w01.attack01() print(Attack.total_power) # s01=Attack('九阳神功',110,90,76) # print(s01.__dict__) # print(Attack.total_power) # s01.attack01() ''' 小明在银行取钱 钱多了 钱少了 ''' class Person: ''' ''' def __init__(self,name,money): self.name=name self.money=money class Bank: def __init__(self,name,total_money,person): self.name=name self.total_money=total_money self.person=person def take_monye(self): if self.total_money>=self.person.money: print('共计有',self.total_money) self.total_money-=self.person.money print(self.person.name,'取走了',self.person.money,self.name,'剩余有',self.total_money,) else: print('金额不足') w01=Person('小明',3500) s01=Bank('招商银行',20000,w01) s01.take_monye() class Wife01: def __init__(self, name="", weight=0): self.name = name # 如果不隐藏数据,外部可以任意操作. # self.weight = weight #给了双下划线weight # self.set_weight(weight) #为了更直观数据,不用通过方法隐藏数据 self.__weight=weight #只能读不能写 # 创建p对象,绑定读取方法 # @property #weight=property(weight,none) # # 读取方法 # def weight(self): # # if 条件 # return self.__weight #*10 # @weight.setter #调动读取方法名 # 写入方法 #只能读的属性 def weight(self,value): if 20 <= value <=200: self.__weight = value else: raise Exception("我不要") weight= property(None,weight) w01=Wife01("小华",49) w01.weight=30 print(w01.__dict__) ''' 封装---设计角度 一个类调用另一个类 ''' # 需求:以面向对象的思想,描述一下情景 # 老张开车去东北 class Person: def __init__(self, name=None, car=None): # 对象数据 self.name = name # self.car=Car() #创造我的车 self.tool = car # 抽象它 我可以使用不同交通工具 def go_to(self): # 对象的行为方法 print(self.name) # Car().run() #Car()创建对象 self.tool.run() # 去哪里都是一辆新车 print('去东北') # 去哪里都是我的那辆车 def go_home(self): self.tool.run() #调用Car.run() print('回家') # 需要调用实例成员(实例) class Car: def run(self): print('开车走你...') bm = Car() lz = Person('老张', bm) lz.go_to() # lz.go_home()
-
设计角度讲
-
定义:
(1) 分而治之
将一个大的需求分解为许多类,每个类处理一个独立的功能。
(2) 变则疏之
变化的地方独立封装,避免影响其他类。
(3) 高 内 聚
类中各个方法都在完成一项任务(单一职责的类)。
(4) 低 耦 合
类与类的关联性与依赖度要低(每个类独立),让一个类的改变,尽少影响其他类。
-
优势:
便于分工,便于复用,可扩展性强。
-
**类有行为,对象有数据
类与类行为不同
对象与对象数据不同
分后合,类与类互相调用
-
案例:信息管理系统
-
需求
实现对学生信息的增加、删除、修改和查询。
-
分析
界面可能使用控制台,也可能使用Web等等。
-
识别对象:界面视图类 逻辑控制类 数据模型类
-
分配职责:
界面视图类:负责处理界面逻辑,比如显示菜单,获取输入,显示结果等。
逻辑控制类:负责存储学生信息,处理业务逻辑。比如添加、删除等
数据模型类:定义需要处理的数据类型。比如学生信息。
-
建立交互:
界面视图对象 <----> 数据模型对象 <----> 逻辑控制对象
-
设计
数据:编号 id,姓名 name,年龄 age,成绩 score
逻辑控制类:StudentManagerController
数据:学生列表 __stu_list
行为:获取列表 stu_list,添加学生 add_student,删除学生remove_student,修改学生update_student,根据成绩排序order_by_score。
界面视图类:StudentManagerView
数据:逻辑控制对象__manager
行为:显示菜单__display_menu,选择菜单项__select_menu_item,入口逻辑main,
输入学生__input_students,输出学生__output_students,删除学生__delete_student,修改学生信息__modify_student
-
继承
老张开车,手雷,图形面积
隔,把儿子抽象化为父亲
儿子是对象,对象行为(对象方法)有共性就到父亲(类:抽象出来的)的(父亲,儿子对象方法,共性)
在闭区间中用:人类:的行为def:(去)
多态:重写
开闭原则:增加新的交通工具,不影响人类
依赖倒置:人类调用交通工具(调用大范围的东东,包含万物的,回本不动),而不调用汽车,飞机
-
语法角度讲
-
继承方法
-
代码:
class 父类:
def 父类方法(self):
方法体
class 子类(父类):
def 子类方法(self):
方法体
儿子 = 子类()
儿子.子类方法()
儿子.父类方法()
-
说明:
子类直接拥有父类的方法.
-
内置函数
isinstance(对象, 类型)
返回指定对象是否是某个类的对象。
issubclass(类型,类型)
返回指定类型是否属于某个类型。
-
继承数据
-
代码
class 子类(父类):
def __init__(self,参数列表):
super().__init__(参数列表)
self.自身实例变量 = 参数
-
说明
子类如果没有构造函数,将自动执行父类的,但如果有构造函数将覆盖父类的。此时必须通过super()函数调用父类的构造函数,以确保父类实例变量被正常创建。
-
定义
重用现有类的功能,并在此基础上进行扩展。
说明:子类直接具有父类的成员(共性),还可以扩展新功能。
-
优点
一种代码复用的方式。
-
缺点
耦合度高:父类的变化,直接影响子类。
class Animal: def eat(self): print('吃') class Dog(Animal): def run(self): print("跑") class Bird(Animal): def fly(self): print('飞') bird01 = Bird() bird01.fly() bird01.eat() a01 = Animal() a01.eat() dog= Dog() # 狗对象 是一种 动物类型 print(isinstance(dog,Animal)) # 狗对象 是一种 狗类型 print(isinstance(dog,Dog)) print(isinstance(a01,Dog)) print(issubclass(Dog,Animal)) print(issubclass(Bird,Animal)) # 狗对象 是 狗类型 print(type(dog)==Dog) # 狗对象 不是 动物类型 print(type(dog)==Animal)
-
设计角度讲
-
定义
将相关类的共性进行抽象,统一概念,隔离变化。
-
适用性
多个类在概念上是一致的,且需要进行统一的处理。
-
相关概念
父类(基类、超类)、子类(派生类)。
父类相对于子类更抽象,范围更宽泛;子类相对于父类更具体,范围更狭小。
单继承:父类只有一个(例如 Java,C#)。
多继承:父类有多个(例如C++,Python)。
Object类:任何类都直接或间接继承自 object 类。
-
多继承(隔离变化)
一个子类继承两个或两个以上的基类,父类中的属性和方法同时被子类继承下来。
同名方法的解析顺序(MRO, Method Resolution Order):
类自身 --> 父类继承列表(由左至右)--> 再上层父类
人 去 交通工具 汽车
手雷 炸 交通工具 汽车
通过类名调用实例方法:B.m01(self)
A
/ \
/ \
B C
\ /
\ /
-
多态
-
设计角度讲
-
定义
父类的同一种动作或者行为,在不同的子类上有不同的实现。
-
作用
-
在继承的基础上,体现类型的个性化(一个行为有不同的实现)。
-
增强程序扩展性,体现开闭原则。
-
语法角度讲
-
重写
子类实现了父类中相同的方法(方法名、参数)。
在调用该方法时,实际执行的是子类的方法。
-
快捷键
Ctrl + O
-
内置可重写函数
Python中,以双下划线开头、双下划线结尾的是系统定义的成员。我们可以在自定义类中进行重写,从而改变其行为。
-
转换字符串
__str__函数:将对象转换为字符串(对人友好的)
__repr__函数:将对象转换为字符串(解释器可识别的)
-
运算符重载
定义:让自定义的类生成的对象(实例)能够使用运算符进行操作。
-
算数运算符
-
反向算数运算符重载
-
复合运算符重载
-
比较运算重载
-
设计原则
-
开-闭原则(目标、总的指导思想)
Open Closed Principle
对扩展开放,对修改关闭。
增加新功能,不改变原有代码。
-
类的单一职责(一个类的定义)
Single Responsibility Principle
一个类有且只有一个改变它的原因。
-
依赖倒置(依赖抽象)
Dependency Inversion Principle
客户端代码(调用的类)尽量依赖(使用)抽象。
抽象不应该依赖细节,细节应该依赖抽象。
-
组合复用原则(复用的最佳实践)
Composite Reuse Principle
如果仅仅为了代码复用优先选择组合复用,而非继承复用。
组合的耦合性相对继承低。
-
里氏替换(继承后的重写,指导继承的设计)
Liskov Substitution Principle
父类出现的地方可以被子类替换,在替换后依然保持原功能。
子类要拥有父类的所有功能。
子类在重写父类方法时,尽量选择扩展重写,防止改变了功能。
-
迪米特法则(类与类交互的原则)
Law of Demeter
不要和陌生人说话。
类与类交互时,在满足功能要求的基础上,传递的数据量越少越好。因为这样可能降低耦合度。
低耦合 〔V 掉用 C 一直交互,如何低耦合?找一个中间的 做爹法
''' day13 复习 面向对象:考虑问题从对象的角度出的发,谁 干嘛? 抽象:对象--> 类 子类1 汽车 子类2 轮船---> 父类(子类中的共性的)交通工具 哲学上的概念:抽象的概念! 从多个事物中,舍弃个性(非本质的)特征. 抽出共性的的本质的过程: 三大特征:变化了怎么办? 封装:分 语法: 用类将多个数据,与对数据的操作整合为一个类型: class 类名: def __init__(self,参数列表): self.数据1 = 参数 def 对象的数据操作(self): 方法体 变量=类名(参数) 设计: 度:活字印刷, 分而治之,变则疏之(行为方法不一样)变化点 飞机 火车... 行业特征:哪里有地方变化 高内聚,低耦合(类之间的变化,影响尽量小) 人调用火车紧耦合 人调用交通工具(隔离)得益于继承 继承:隔(由分到合) 抽象出多个子类的共性(火车类,飞机类 共性:交通工具类 共同的行为方法:运输()) 语法: 继承方法:子类直接可以使用父类方法 继承数据: 子类没有构造函数__init__使用父类的 子类有构造函数,则需要调用父类构造函数super().__init_() class 父类: def __init__(self,爸爸的参数): self.爸爸的数据=爸爸参数 (方法行为) class 子类(父类): def __init__(self, 爸爸的参数,儿子参数) super().__init_(爸爸的参数) self.儿子的数据= 儿子的参数 设计: 抽象变化,隔离变化 继承方法: class 父类: def 父类对象的数据操作(self,爸爸的参数): self.爸爸的数据=爸爸参数 (方法行为) class 子类(父类): def __init__(self, 爸爸的参数,儿子参数) super().__init_(爸爸的参数) self.儿子的数据= 儿子的参数 多态:干 语法:调用父类方法,在不同子类上执行效果不同 class 父类: def 功能1(self): ... class 子类(父类): # 3 .子类重写 def 功能1(self) ... 变量=父类() 变量,功能1() 不是多态 变量=子类() 变量,功能1() 不是多态 更 def 函数(父类型参数): #1 .调用父类方法 父类型参数.功能1() #2 . 传递不同的子类对象 函数(子类()) 直接调儿子,把代码写死了 不灵活 以不变应万变 设计:增加程序的灵活度(子类替换父类自行不同逻辑) 设计原则:封装,继承,多态 的指导(粗化) 六大原则: 1.开闭原则:可以增加新功能,不能允许修改客户端代码(调用方). 2.类的单一职责(一个类的定义 一个函数也一个功能, 火车,而不是运输),一个类有且只有一个改变它的原因 3.依赖倒置 调用父类,不调用子(因为子是变化的); 客户端代码(调用的类)尽量依赖(使用)抽象 抽象不依赖细节,细节依赖抽像 4.组合复用原则:组合复用,非继承复用(就两用复用) class A: def a(self): print("a") class B(A): def b(self): print("b") # 继承复用 super().a() b01 = B() b01.b() 优点:直接使用,简单省事 缺点:紧耦合 一块内存,破坏了封装性, 耦合太高 父类变化,子影响 设计原则:组合复用 组合是类与类之间的关系 通过变量调用,而不是通过继承复用 ''' ''' 练习题 定义员工管理器 1,记录所有员工 2,提供计算总工资的方法 员工种类: 程序员:底薪+项目分红 测试员:底薪_bug数*5元 ... 要求:增加新员工种类,不影响员工管理器 体会:继承与组合 ''' class PersonnelManager: def __init__(self): self.__per_list=[] def add_per(self,per_target): self.__per_list.append(per_target) def total_per(self): count = 0 for item in self.__per_list: count +=item.account() return count class Fu: def __init__(self,dixin): self.dixin=dixin def account(self): return self.dixin class Son1(Fu): def __init__(self,dixin, fenhong): super().__init__(dixin) self.fenhong = fenhong def account(self): return super().account()+self.fenhong #里氏替换 class Son2(Fu): def __init__(self,dixin,bug ): super().__init__(dixin) self.bug=bug def account(self): return self.dixin+self.bug*5 p01 =PersonnelManager() s01 = Son1(5000,8000) s02 = Son2(3000,40) p01.add_per(s01) p01.add_per(s02) print(p01.total_per())