面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到必定阶段后的产物。面向对象编程(OOP)具体说是一种程序开发方法,一种编程思想、范式。你能够粗滤的理解为,项目经理干的活就是面向对象,负责分配任务,而coder干的活就是面向过程,负责具体任务的实施细节。
python
1.公式:程序 = 对象 + 交互程序员
2.优势算法
(1) 思想层面:编程
-- 可模拟现实情景,更接近于人类思惟。python3.x
-- 有利于梳理概括、分析解决问题。数据结构
(2) 技术层面:app
-- 高复用:对重复的代码进行封装,提升开发效率。函数
-- 高扩展:增长新的功能,不修改之前的代码。工具
-- 高维护:代码可读性好,逻辑清晰,结构规整。学习
3.缺点:学习曲线陡峭。
1.类(class):具备相同属性(实例变量)和行为(实例方法)的对象的抽象。实际上就是一种自定义的数据类型,类也有对应的类变量和类方法。
2.对象(instance):类的具体实例,即归属于某个类别的”个体”。
3.属性和行为:类与类方法不一样,对象与对象属性值不一样。
1.格式
class 类名(object):
“””文档说明”””
def _init_(self,参数列表):
self.实例变量名= 参数(形参)
def 实例方法名(self,参数列表):
pass
2.说明
-- 类名全部单词首字母大写,多个单词不用下划线隔开,采用驼峰体。
-- (object)是表示该类是从object类继承下来的,python3.x版本可省略。
-- __init__也叫构造函数,建立对象时被调用,也能够省略。
-- self绑定的是被建立的对象的内存地址,名称能够随意。
拓展:object类和type类的区别,即基类与元类的区别
1.object类是继承层面的:其余的类或者对象都是经过继承的关系,直接或者间接的继承了object,翻阅全部对象的族谱,最后必定会发现它们的老祖宗就是object。
1 >>>list.__base__ #Python为全部类都提供了一个__bases__属性,经过该属性能够查看该类的全部直接父类,该属性返回全部直接父类组成的元组 (<class 'object'>,) 2 >>>type.__bases__ (<class 'object'>,) 3 >>>object.__bases__ #object类是全部类的基类 ()
2.type类是类建立对象层面的:python中一切皆对象,数据、对象是由str、list等数据类型和自定义类建立的,而全部数据类型和自定义类都是由元类建立的
1 >>> type(list) <class 'type'> 2 >>> type(object) <class 'type'> 3 >>> type(type) <class 'type'> #type类是全部类的元类,可是其自己是由虚拟机建立的
1.格式
变量 = 类名 (实参数列表)
2.说明
-- python中无处不对象,对象是python中对数据的一种抽象的表示
-- 全部对象都有三种特性:id、类型、值
id:对象的内存地址,由变量关联,查看经过:id(变量)
类型:生成对象的模型,对应类名,查看经过:type(变量)
值:对象中存放的数据,对应实参列表,查看经过:变量.__dict__
-- 每一个对象都是由其对应的类建立出来的
拓展:与对象的建立,调用,删除相关的魔法方法:__new__()方法,__init__()方法,__call__()方法,__del__()方法
1.__new__()方法和__init__()方法:__new__()方法是一个类方法,在对象被建立的时候调用,该方法负责建立(实例化)一个对象。若是建立对象成功,该对象会自动的调用__init__()方法,对自身进行初始化,若是建立对象失败,没有对象了,天然也就没谁去调用__init__()方法了。
2.__call__()方法:若是类中定义了该方法,可使对象成为像函数和类同样的可调用对象。
1 class Entity: 2 ''' 3 调用实体来改变实体的位置。 4 ''' 5 6 def __init__(self, size, x, y): 7 self.x, self.y = x, y 8 self.size = size 9 10 def __call__(self, x, y): 11 '''改变实体的位置''' 12 self.x, self.y = x, y 13 14 15 e = Entity(1, 2, 3) # 建立实例 16 print(e.__dict__) # {'x': 2, 'y': 3, 'size': 1} 17 e(4, 5) # 实例能够象函数那样执行,并传入x y值,修改对象的x y 18 print(e.__dict__) # {'x': 4, 'y': 5, 'size': 1}
3.__del__()方法:是python垃圾回收机制的实际应用,当类中定义了该方法时,建立的对象的引用计数为0时该方法被调用
>>> class D(object): def __init__(self): print 'this is D.__init__()' def __del__(self): print 'this is D.__del__()' >>> d = D() this is D.__init__() >>> d2 = d >>> d3 = d >>> >>> del d >>> del d2 >>> del d3 #当对象的引用计数为0时自动触发__del__()方法 this is D.__del__()
1.语法
(1) 定义:对象地址.变量名=数据值
(2) 调用:对象地址.变量名=数据值
2.说明
(1) 首次经过对象赋值为建立,再次赋值为修改。
(2) 一般在__init__构造函数中(self.实例变量名=形参)建立,建立对象时赋值。也能够在
(3) 每一个对象存储一份,经过对象地址访问。
3.做用:描述对象自身的数据。
4.__dict__:对象的属性,用于存储自身实例变量(包括私有化变量)的字典。
1.语法
(1) 定义: def 方法名称(self, 形参列表):
方法体
(2) 调用: 对象地址.实例方法名(实参列表)
2.说明
(1) 定义时至少有一个形参,通常命名为"self",用于绑定调用这个方法的对象地址,经过对象调用实例方法时self不用传参。
(2)每一个对象共用一份,经过对象地址访问。不建议经过类名访问实例方法(对象与对象数据值不一样,经过类名调用实例方法时,须要给self参数传参具体的对象)
3.做用:表示对象行为。
1 """ 2 实例成员 3 记住一句话:实例成员,使用对象地址访问. 4 """ 5 class Student: 6 pass 7 8 s01 = Student() 9 # 定义实例变量: 对象.变量名 = 数据值 10 s01.name = "lennie" 11 print(s01.name) #"lennie" 12 s02 = Student() 13 # print(s02.name)# AttributeError,由于s02指向的对象,没有建立过实例变量name 14 # 经过__dict__获取当前对象的全部实例变量 15 print(s01.__dict__) #{'name': 'lennie'} 16 print(s02.__dict__) #{} 17 18 19 class Student02: 20 def __init__(self, name, height): 21 self.name = name 22 self.height = height 23 24 # 实例方法 25 def print_self(self): 26 print(self.name,self.height) 27 28 29 s01 = Student02("lennie", 170) 30 s02 = Student02("ginger", 162) 31 # 建议:实例方法,经过对象地址访问. 32 s01.print_self() 33 # 不建议:Student02.print_self(),若没有传递对象地址,实例方法不能正确访问对象数据. 34 Student02.print_self(s02)
1.语法
(1) 定义:在类中,方法外定义变量。
class 类名:
变量名 = 表达式
(2) 调用:类名.变量名
不建议经过对象访问类变量
2.说明
(1) 存储在类中。
(2)全部对象共享一份,可经过类或者对象直接调用。
3.做用:描述全部对象的共有数据。
1.语法
(1) 定义:
@classmethod
def 方法名称(cls,形参列表):
方法体
(2) 调用:类名.方法名(实参列表)
不建议经过对象访问类方法
2.说明
(1) 至少有一个形参,通常命名为'cls',用于绑定类的内存地址。
(2) 使用@classmethod修饰的目的是调用类方法时能够隐式传递类,即经过类名调用类方法时cls不须要传参。
(3) 类方法中不能访问实例成员,实例方法中能够访问类成员。
3.做用:操做类变量。
1 """ 2 类成员,用类的地址去访问 3 """ 4 class ICBC: 5 # 类变量:总行的钱 6 total_money = 1000000 7 # 类方法 8 @classmethod 9 def print_total_money(cls): 10 # print(id(cls), id(ICBC)) 11 # cls : 存储当前类的地址 12 # print("当前总行金额:",ICBC.total_money) 13 print("当前总行金额:", cls.total_money) 14 15 def __init__(self, name, money): 16 self.name = name 17 self.money = money 18 # 从总行扣除当前支行的钱 19 ICBC.total_money -= money 20 21 22 i01 = ICBC("天坛支行", 100000) 23 i02 = ICBC("陶然亭支行", 100000) 24 # 主流:经过类访问类成员 25 ICBC.print_total_money() #"当前总行金额: 800000" 26 print(ICBC.total_money) #800000 27 # 非主流:经过对象访问类成员 28 # print(i02.total_money) 29 # i02.print_total_money()
1.语法
(1) 定义:
@staticmethod
def 方法名称(形参列表):
方法体
(2) 调用:类名.方法名(实参列表)
不建议经过对象访问静态方法
2.说明
(1) 使用@ staticmethod修饰的目的是该方法不须要隐式传参数,即参数列表不含self,cls参数,其实就是个函数
(2) 静态方法不能访问实例成员和类成员
3.做用:定义经常使用的工具函数。
1.定义:将一些基本属性封装成共有属性,类的建立中的__init__初始化
2.优点:将数据与对数据的操做相关联,代码可读性(相比容器)更高(类是对象的模板)。
定义:类外提供必要的功能,隐藏实现的细节,私有化操做
优点:简化编程,使用者没必要了解具体的实现细节,只须要调用对外提供的功能。
私有成员:
(1) 做用:只有类内部能够直接访问,外部不能直接访问,能够对参数作检查,避免传入无效的参数
(2) 作法:__成员名
(3) 本质:障眼法,实际也能够访问。私有成员的名称被修改成:_类名__成员名,能够经过_dict_属性或dir函数查看。
1 class Coder: 2 """ 3 私有成员的读和写操做 4 """ 5 def __init__(self, name, age): 6 self.name = name 7 self.__age = age #私有化方式一:私有成员命名采用双下划线开头 8 # self.set_age(age) #私有化方式二 9 10 # 使用两个公开的方法获取和修改私有属性 11 def get_age(self): 12 return self.__age # 类内部访问无限制 13 14 def set_age(self, value): 15 if 0 <= value <= 100: # 检验数据的有效性,限制随意更改属性值 16 self.__age = value 17 else: 18 raise ValueError 19 20 age=property(get_age,set_age) #无读写限制 21 # age=property(get_age,None) #写限制 22 # age=property(None,set_age) #读限制 23 # age=property(None,None) #读写均限制 24 25 c = Coder("lennie", 26) 26 # 1.私有成员不能直接访问 27 print(c.__age) #AttributeError: 'Coder' object has no attribute '__age' 28 print(c.__dict__) # {'name': 'lennie', '_Coder__age': 26} 29 # 2.可经过 对象._类名__成员名 访问(此种访问无限制) 30 c._Coder__age = 27 31 print(c._Coder__age) # 27 32 # 3.可经过两个私有方法实现私有成员的读写(此种方式可限制私有成员被随意改写) 33 c.set_age(30) 34 print(c.get_age()) # 30 35 #4.可经过设置property(读方法名,写方法名),实现私有成员的读写 36 c.age=32 37 print(c.age) #32
4.属性@property:
公开的实例变量,缺乏逻辑验证。私有的实例变量与两个公开的方法相结合,又使调用者的操做略显复杂。而属性能够将两个方法的使用方式像操做变量同样方便。
(1) 定义:
@property #容许读,等价于定义类变量:属性名=property(读方法名,None)
def 属性名(self):
return self.__属性名
@属性名.setter #容许写,等价于定义类变量:属性名=property(读方法名,None)
def 属性名(self, value):
self.__属性名= value
(2) 调用:
对象.属性名 = 数据
变量 = 对象.属性名
(3) 说明:
1 class Coder: 2 """ 3 @property和@私有成员名.setter 4 """ 5 def __init__(self, name, age): 6 self.name = name 7 self.__age = age #私有成员 8 9 @property 10 def age(self): 11 return self.__age 12 13 @age.setter 14 def age(self, value): 15 if 0 <= value <= 100: # 检验数据的有效性,限制随意更改属性值 16 self.__age = value 17 else: 18 raise ValueError 19 20 c=Coder("lennie",26) 21 # print(c.__age) #依然不能直接调用,AttributeError 22 #1.可直接由_类名__属性名调用 23 c._Coder__age=27 24 print(c._Coder__age) #27 25 #2.避免使用两个方法的繁琐,使私有成员如变量般调用 26 c.age=30 27 # c.age=120 #ValueError 28 print(c.age) #30
(1) 分而治之
将一个大的需求分解为许多类,每一个类处理一个独立的功能。 设计角度看类的建立应先考虑方法(行为,干什么),在考虑初始化(数据)
(2) 变则疏之 #拆分的度
变化的地方独立封装,避免影响其余类。
(3) 高 内 聚
类中各个方法都在完成一项任务(单一职责的类)。
(4) 低 耦 合 #低不是杜绝,是有互相调用才能完成
类与类的关联性与依赖度要低(每一个类独立),让一个类的改变,尽少影响其余类。
2.优点:
便于分工,便于复用,可扩展性强。
class 父类:
def 父类方法(self):
方法体
class 子类(父类):
def 子类方法(self):
方法体
儿子 = 子类()
儿子.子类方法()
儿子.父类方法()
2.说明:子类直接拥有父类的方法.
1 """ 2 继承 -- 方法 3 编程:代码不用子类写,可是能够用. 4 """ 5 class Person: 6 def say(self): 7 print("说话") 8 9 class Student(Person): 10 def study(self): 11 print("学习") 12 13 class Teacher(Person): 14 def teach(self): 15 print("讲课") 16 17 # 建立父类型对象,只能访问父类型成员 18 p01 = Person() 19 p01.say() 20 21 # 建立子类型对象,能访问父类型成员,还能访自身成员 22 s01 = Student() 23 s01.say() 24 s01.study() 25 26 # "是否是 实例" 27 # s01的对象 是一种 Student类型 28 print(isinstance(s01,Student))# True 29 print(isinstance(s01,Person))# True isinstance用于鉴定对象的直接模板以及其父模板 30 print(isinstance(s01,Teacher))# False 31 32 # s01的类型 等于 Student类型 33 print(type(s01) == Student)# True 34 print(type(s01) == Person)# False type只能断定对象的直接模板 35 36 # Student 类型 是一种 Person类型 37 print(issubclass(Student,Person))# True 38 print(issubclass(Student,Student))# True 39 print(issubclass(Student,Teacher))# False issubclass用于鉴定两个类是否有亲属关系
class 子类(父类):
def __init__(self,参数列表):
super().__init__(参数列表)
self.自身实例变量 = 参数
2.说明
子类若是没有构造函数,将自动执行父类的,但若是有构造函数将覆盖父类的,此时必须经过super()函数调用父类的构造函数,以确保父类实例变量被正常建立。
重用现有类的功能,并在此基础上进行扩展。子类直接具备父类的成员(共性),还能够扩展新功能。
1 """ 2 继承 -- 数据 3 """ 4 class Person: 5 def __init__(self, name=""): 6 self.name = name 7 8 class Student(Person): 9 def __init__(self, name="", score=0): 10 # self.name = name 11 # 若是子类没有构造函数,使用父类构造函数 12 # 若是子类有构造函数,必须铜经过super()调用父类构造函数, 13 # 不然会覆盖父类(不执行)的. 14 super().__init__(name) 15 self.score = score 16 17 18 # 建立实例变量 19 s01 = Student("lennie", 100) 20 print(s01.name) #"lennie" 21 print(s01.score) #100 22 p01 = Person("ginger") 23 print(p01.name) #"ginger" 24 print(p01.score) #报错AttributeError,子直接继承父,但父不能调用子类成员
一种代码复用的方式。
耦合度高:父类的变化,直接影响子类。
将相关类的共性进行抽象,统一律念,隔离变化。类是对象的抽象,同理父类是子类的抽象。
多个类在概念上是一致的,且须要进行统一的处理。
1 """ 2 继承 -- 设计角度。隔离变化 3 老张开车去东北. 4 需求变化:还可能坐飞机,坐火车...... 5 """ 6 7 8 class Person: 9 def __init__(self, name=""): 10 self.name = name 11 12 def go_to(self,str_position,vehicle): 13 #经过一个参数vehicle将对象传递进来,从而调用方法transport(),
鸭子类型的概念(此处传入的对象只要有transport()方法,就视为也是Vehicle类型,并不是必定是其子类) 14 print(self.name,vehicle.transport(),"去",str_position,sep="") 15 16 17 class Vehicle: 18 """ 19 交通工具类,抽象的 20 将共有的功能(运输)进行提取,供其子类对象继承复用 21 """ 22 def transport(self): 23 pass 24 25 # -------------------------------------隔离变化 26 class Car(Vehicle): 27 28 def transport(self): 29 return "坐车" 30 31 class Airplane(Vehicle): 32 33 def transport(self): 34 return "坐飞机" 35 36 37 c01 = Car() 38 a01 = Airplane() 39 lz = Person("老张") 40 lz.go_to("东北",c01) #老张坐车去东北 41 lz.go_to("东北",a01) #老张坐飞机去东北
一个子类继承两个或两个以上的基类,父类中的属性和方法同时被子类继承下来。
MRO(Method Resolution Order)查看同名方法的解析顺序:print(D.mro)类自身 --> 父类继承列表(由左至右)--> 再上层父类
A
/ \
B C
\ /
D
1 class A: 2 pass 3 class B(A): 4 pass 5 class C(A): 6 pass 7 class D(B,C): 8 pass 9 10 print(D.mro())#[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] 11 print(C.mro())#[<class '__main__.C'>, <class '__main__.A'>, <class 'object'>] 12 print(B.mro())#[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>] 13 print(A.mro())#[<class '__main__.A'>, <class 'object'>]
父类的同一种动做或者行为,在不一样的子类上有不一样的实现。
子类中定义(def)了父类中同名的方法(方法名、参数)。虽然该同名方法在子类中定义了,依然认为是父类的方法。
在调用该方法时,实际执行的是子类的方法。
Ctrl + O
Python中,以双下划线开头、双下划线结尾的是系统定义的成员。咱们能够在自定义类中进行重写,从而改变其行为。
__str__函数:将对象(打印时显示内存地址)转换为字符串(打印对象时显示自定义字符串)(对人友好的)
__repr__函数:将对象转换为字符串(解释器可识别的)
1 """ 2 内置可重写函数 3 自定义对象 --> str 4 """ 5 class Car: 6 def __init__(self, brand="", price=0,max_speed = 0): 7 self.brand = brand 8 self.price = price 9 self.max_speed = max_speed 10 11 # # 对人友好的,为所欲为的规定字符串内容-->将<__main__.Car object at 0x...>转换为自定义的字符串 12 # def __str__(self): 13 # return "品牌是%s,单价是%d"%(self.brand,self.price) 14 15 # 对解释器友好,根据python语法规定字符串内容-->功能同__str__(),可是更强大,一般与eval("")配合使用 16 def __repr__(self): 17 return "Car('%s',%d,%d)"%(self.brand,self.price,self.max_speed) 18 19 # 应用:将对象换成自定义的字符串显示出来 20 c01 = Car("宝马",1000000,260) 21 print(c01) #"品牌是宝马,单价是1000000",会自动调用c01.__str__()方法 22 #当已经定义了__str__()时必须显式调用c01.__repr__()或者repr(c01)才会执行 23 print(c01.__repr__()) #"Car('宝马',1000000,260)"
拓展:eval("代码")函数
>>> eval("1+2") 3 >>> eval("lennie") #等价于在命令行直接输入lennie NameError: name 'lennie' is not defined >>> lennie NameError: name 'lennie' is not defined >>>
4.应用:eval("")函数与__repr__()方法配合使用,实现深拷贝对象
1 # 定义技能类(技能名称,攻击比例,持续时间) 2 # 建立技能对象,直接print对象. 3 # 克隆(深拷贝)技能对象,体会改变其中一个,不影响另一个. 4 5 class Skill: 6 def __init__(self, name="", atk_ratio=0.1, duration=0.1): 7 self.name = name 8 self.atk_ratio = atk_ratio 9 self.duration = duration 10 11 def __str__(self): 12 return "%s---%d---%d" % (self.name, self.atk_ratio, self.duration) 13 14 def __repr__(self): 15 return "Skill('%s',%d,%d)" % (self.name, self.atk_ratio, self.duration) 16 17 18 s01 = Skill("佛怒火莲", 3, 5) 19 print(s01) #佛怒火莲---3---5 20 21 # s02 = eval("Skill('佛怒火莲',3,5)") 22 s02 = eval(s01.__repr__()) 23 s01.name = "焰分噬浪尺" 24 print(s02) #佛怒火莲---3---5
定义:让自定义的类生成的对象(实例),可以像str、int、list类型数据对象同样,使用运算符进行操做。
1 """ 2 运算符重载(重写) 3 """ 4 5 # 多态:调用父,执行子. 6 class Vector: 7 """ 8 向量 9 """ 10 11 def __init__(self, x=0): 12 self.x = x 13 14 def __str__(self): 15 return "份量是:" + str(self.x) 16 17 # 算数运算符 --> 返回新结果 18 def __add__(self, other): 19 """ 20 当前对象与其余数据相加时被自动调用 21 :param other: 其余数据 22 :return: 向量 23 """ 24 # 若是other 是 向量 25 if type(other) == Vector: 26 return Vector(self.x + other.x) 27 # 不然 28 else: 29 return Vector(self.x + other) 30 31 def __rsub__(self, other): 32 return Vector(other - self.x) 33 34 # 复合运算符 --> 在原有对象基础上修改 35 def __iadd__(self, other): 36 self.x += other 37 return self 38 39 def __gt__(self, other): 40 return self.x > other.x 41 42 # 1. 算数运算符 43 v01 = Vector(10) 44 # 自定义向量 + 整数 --> 向量 45 print(v01 + 5) # v01.__add__(5) 46 # 自定义向量 + 自定义向量 --> 向量 47 v02 = Vector(2) 48 print(v01 + v02) 49 50 # 2. 反向算数运算符 51 # 整数 - 自定义向量 --> 向量 52 print(5 - v01) # v01.__rsub__(5) 53 54 """ 55 list01 = [1] 56 57 # print(id(list01)) 58 list01 += [2]# 在原有基础上增长新元素 59 # print(id(list01)) 60 61 # print(id(list01)) 62 list01 = list01 + [3]# 产生新的对象 63 # print(id(list01)) 64 65 print(list01) 66 """ 67 68 # 3. 复合运算符 69 # 默认使用算数运算符 70 print(id(v02)) 71 v02 += 3 # v02 = v02 + 3 72 print(v02) 73 print(id(v02)) 74 75 # 4. 比较运算符 76 # 自定义类 > 自定义类 77 print(v01 > v02)# v01.__gt__(v02)
Open Closed Principle
对扩展开放,对修改关闭。
增长新功能,不改变原有代码。
Single Responsibility Principle
一个类有且只有一个改变它的缘由。
Dependency Inversion Principle
客户端代码(调用的类)尽可能依赖(使用)抽象。
抽象不该该依赖细节,细节应该依赖抽象。
Composite Reuse Principle
若是仅仅为了代码复用优先选择组合复用,而非继承复用。
组合的耦合性相对继承低。
Liskov Substitution Principle
父类出现的地方能够被子类替换,在替换后依然保持原功能。
子类要拥有父类的全部功能。
子类在重写父类方法时,尽可能选择扩展重写,防止改变了功能。在Ctrl+o时,别删东西,重写后扩展重写
Law of Demeter
不要和陌生人说话。
类与类交互时,在知足功能要求的基础上,传递的数据量越少越好。由于这样可能下降耦合度(利用抽象去调用子类,隔离变化)。
1 """ 2 面向对象的应用: 3 定义员工管理器,记录全部员工,计算总工资. 4 程序员:底薪 + 项目分成 5 测试员:底薪 + bug * 5 6 要求:增长新的岗位,不影响员工管理器. 7 指出:三大特征,六个原则. 8 9 封装:员工管理器,程序员,测试员 10 继承:员工隔离员工管理器与具体员工的变化 11 多态:员工管理器调用员工,执行程序员,测试员. 12 开闭:增长新的岗位,不影响员工管理器. 13 单一:员工管理器(管理员工),员工(隔离变化),程序员(计算薪资),测试员(计算薪资) 14 依赖倒置:员工管理器调用员工,而不调用程序员/测试员 15 组合复用:员工管理器存储具体员工的变量
里氏替换:程序员(继承员工底薪后添加奖金),测试员(继承员工底薪后添加bug提成)
迪米特法则:员工管理器与程序员,测试员的交互,改由与员工交互,减小了数据的传递
16 """ 17 18 19 class EmployeeManager: 20 """ 21 员工管理器 22 """ 23 24 def __init__(self): 25 self.__all_employee = [] 26 27 def add_employee(self, emp): 28 # 判断 emp 是员工 则 添加....? 29 # if type(emp) == Employee: 30 # emp 属于 员工 31 if isinstance(emp, Employee): 32 self.__all_employee.append(emp) 33 34 def get_total_salary(self): 35 total_sarlay = 0 36 for itme in self.__all_employee: 37 # 调用的是员工 38 # 执行的是程序员/测试员 39 total_sarlay += itme.calculate_salary() 40 return total_sarlay 41 42 43 class Employee: 44 """ 45 员工 46 抽象的 --> 统一律念 --> 隔离变化 47 48 """ 49 50 def __init__(self, base_salary): 51 self.base_salary = base_salary 52 53 def calculate_salary(self): 54 """ 55 计算薪资 56 :return: 小数类型的薪资 57 """ 58 return self.base_salary 59 60 61 class Programmer(Employee): 62 """ 63 程序员 64 """ 65 66 def __init__(self, base_salary=0, bonus=0): 67 super().__init__(base_salary) 68 self.bonus = bonus 69 70 def calculate_salary(self): 71 # return self.base_salary + self.bonus 72 return super().calculate_salary() + self.bonus 73 74 75 class Tester(Employee): 76 def __init__(self, base_salary=0, bug_count=0): 77 super().__init__(base_salary) 78 self.bug_count = bug_count 79 80 def calculate_salary(self): 81 return super().calculate_salary() * self.bug_count * 5 82 83 # def calculate_salary(self): 84 # return self.base_salary * self.bug_count * 5 85 86 manager = EmployeeManager() 87 p01 = Programmer(32000, 50000) 88 manager.add_employee(p01) 89 manager.add_employee(Tester(8000, 2)) 90 print(manager.get_total_salary())