面向对象式编程: 上帝视角
一, 面向对象初识
-
回顾面向过程编程VS函数式编程
-
函数式编程的优点
-
减少代码的重用性
-
增强代码的可读性
-
-
函数式编程VS面向对象编程
- 面向对象编程的优点
- 是一类相似功能函数的集合,使代码更清晰化,更合理化
- 面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板,对象就从具体的模板实例化出来
-
类的结构
class Human: """ 此类主要是构建人类 """ mind = '有思想' # 第一部分:静态属性 属性 静态变量 静态字段 dic = {} l1 = [] def work(self): # 第二部分:方法 函数 动态属性 print('人类会工作') # class 是关键字与def用法相同,定义一个类。 # Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。 # 类的结构从大方向来说就分为两部分: # 静态变量 # 动态方法
二, 从类名的角度研究类
-
类名操作静态属性
# 第一种:查看类中的所有内容: 类名.__dict__方式 class Human: mind = '有思想' dic = {} l1 = [] def work(self): print('人类会工作') print(Human.__dict__) # 查看所有内容 print(Human.__dict__['mind']) Human.__dict__['mind'] = '无脑' # 报错 print(Human.__dict__) # 通过这种方式只能查询,不能增删改.一般只用于查询全部内容(一般不用单独属性查询) ------------------------------------------------------- # 第二种: 万能的点 print(Human.mind) # 查 Human.mind = '无脑' # 改 print(Human.mind) del Human.mind # 删 Human.walk = '直立行走' print(Human.walk) # 通过万能的点 可以增删改查类中的单个属性
总结: 如果想查询类中的所有内容,通过类名.
__dict__
方法,如果只是操作单个属性则用万能的点的方式 -
类名操作动态方法
# 除了两个特殊的方法: 静态方法,类方法之外,一般不会通过类名操作一个类中的方法 class Human: mind = '有思想' dic = {} l1 = [] def work(self): print('人类会工作') def tools(self): print('人类会使用工具') Human.work(111) Human.tools(111) # 下面可以做,但不用。 Human.__dict__['work'](111)
三, 从对象的角度研究类
-
什么是对象?
对象是从类中出来的,只要是类名加上(),这就是一个实例化过程,这个就会实例化一个对象
class Human: mind = '有思想' def __init__(self): print(666) print(self) # <__main__.Human object at 0x00000191508AA828> def work(self): print('人类会工作') def tools(self): print('人类会使用工具') obj = Human() # 只要实例化对象,它会自动执行__init__方法 print(obj) # <__main__.Human object at 0x00000191508AA828> # 并且obj的地址与self的地址相同
实例化一个对象会发生三件事:
- 在内存开辟一个对象空间
- 自动执行类中的
__init__
方法,并将这个对象空间(内存地址)传给了__init__
方法的第一个位置参数self - 在
__init__
方法中通过self给对象空间封装属性
class Human: mind = '有思想' language = '使用语言' def __init__(self,name,sex,age,hobby): # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。 self.n = name self.s = sex self.a = age self.h = hobby obj = Human('barry','男',18,'运动')
-
对象操作对象空间属性
# 对象查询对象中所有属性: 对象.__dict__ print(obj.__dict__) # {'n': 'barry', 'h': '运动', 's': '男', 'a': 18} # 对象操作对象中的单个属性: 万能的点. obj.job = 'IT' # 增 del obj.n # 删 obj.s = '女' # 改 print(obj.s) # 查 print(obj.__dict__)
-
对象查看类中的属性
class Human: mind = '有思想' language = '实用语言' def __init__(self,name,sex,age,hobby): self.n = name self.s = sex self.a = age self.h = hobby obj = Human('barry','男',18,'运动') print(obj.mind) print(obj.language) obj.a = 666 print(obj.a)
-
对象操作类中的方法
class Human: mind = '有思想' language = '实用语言' def __init__(self,name,sex,age,hobby): self.n = name self.s = sex self.a = age self.h = hobby def work(self): print(self) print('人类会工作') def tools(self): print('人类会使用工具') obj = Human('barry','男',18,'运动') obj.work() obj.tools()
类中的方法一般都是通过对象执行的(除去类方法,静态方法外),并且对象执行这些方法都会自动将空间传给方法中的第一个参数self
-
self是什么
self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self,所以咱们把类中的方法的第一个参数约定俗成设置成self,代表这个就是对象
-
一个类可以实例化多个对象
obj1= Human('小胖','男',20,'美女') obj2= Human('小马','女',18,'帅哥') print(obj1,obj2) print(obj1.__dict__) print(obj2.__dict__)
四, 从空间的角度研究类
一, 类的空间问题
-
何处可以添加对象属性
class A: def __init__(self, name): self.name = name def func(self, sex): self.sex = sex # 类外面可以 obj = A('太上老君') obj.age = 18 print(obj.__dict__) # {'name': '太上老君', 'age': 18} # 类内部也可以 obj = A('元始天尊') # __init__方法可以 obj.func('男') # func 方法也可以 print(obj.__dict__) # {'name': '元始天尊', 'sex': '男'} # 总结: 对象的属性不仅可以在__init__里面添加,还可以在类的其他地方或者类的外面添加
-
何处可以添加类的静态属性
class A: def __init__(self, name): self.name = name def func(self, sex): self.sex = sex def func1(self): A.bbb = 'ccc' # 类的外部可以添加 A.aaa = 'dsb' print(A.__dict__) # 类的内部也可以添加 A.func1(111) print(A.__dict__) # 总结: 类的属性不仅可以在类内部添加,还可以在类的外部添加
-
对象和类查找属性的顺序:
-
对象之所以可以找到类,是因为对象空间中有类对象指针这么个东西
-
对象查找属性的顺序:
对象空间>类空间>父类空间==>...
-
类名查找属性的顺序:
本类空间>父类空间>...
-
查找顺序是单项不可逆的,类名不可能找到对象的属性
-
二, 类与类之间的关系
-
依赖关系:
- 将一个类的对象或者类名传到另一个类的方法使用,这两个类之间就是依赖关系
# 大象进冰箱 class Elephant: def __init__(self, name): self.name = name def open_(self, self2): print(f'{self.name}大象打开冰箱门') self2.open_door() # 依赖关系还是通过原对象.的方式调用方法 def close_(self, self2): print(f'{self.name}大象关上冰箱门') self2.close_door() class Refrigerator: def __init__(self, name): self.name = name def open_door(self): print(f'{self.name}冰箱门被打开了') def close_door(self): print(f'{self.name}冰箱门被关上了') daxiang = Elephant('奇奇') bingxiang = Refrigerator('格力') daxiang.open_(bingxiang) daxiang.close_(bingxiang) # 奇奇大象打开冰箱门 # 格力冰箱门被打开了 # 奇奇大象关上冰箱门 # 格力冰箱门被关上了
-
关联,聚合,组合关系(在python中统一叫组合关系)
- 组合关系:将一个类的对象封装到另一个类的对象的属性中,就叫组合
# 男孩的女朋友 class Boy: def __init__(self, name, girlfriend=None): self.name = name self.girlfriend = girlfriend # 将另一个对象作为属性,封装到本对象中 def have_a_diner(self): if self.girlfriend: print(f'{self.name}和{self.girlfriend.name}一起吃晚饭.') self.girlfriend.shopping(self) # 组合关系是以当前对象为主体调用另一个对象的方法 else: print('单身狗,吃什么饭.') class Girl: def __init__(self, name): self.name = name def shopping(self, self2): print(f'{self.name}和{self2.name}一起去购物') b = Boy('小明') b.have_a_diner() # 此时单身狗 g = Girl('小丽') b.girlfriend = g # 有了女朋友 b.have_a_diner() gg = Girl('小花') bb = Boy('小李', gg) bb.have_a_diner() bb.girlfriend = None # 分手了 bb.have_a_diner()
# 学校和老师 class School: def __init__(self, name, address): self.name = name self.address = address class Teacher: def __init__(self, name, school): self.name = name self.school = school s1 = School('北京大学', '喧哗的北京') s2 = School('浙江大学', '美丽的浙江') s3 = School('武汉大学', '美女如云的武汉') t1 = Teacher('王健林', s1) t2 = Teacher('马云', s2) t3 = Teacher('董明珠', s3) print(t1.school.name) print(t2.school.name) print(t3.school.name)
# 设计一个游戏人物类,实例化几个对象让这几个游戏人物实现互殴的效果 class Gamerole: def __init__(self, name, ad, hp): self.name = name self.ad = ad self.hp = hp def attack(self, p1): p1.hp -= self.ad print(f'{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血') # 再写个武器类 class Weapon: def __init__(self, name, ad): self.name = name self.ad = ad def weapon_attack(self, p1, p2): p2.hp = p2.hp - p1.ad - self.ad print(f'{p1.name}利用{self.name}攻击了{p2.name},{p2.name}还剩{p2.hp}血') gailun = Gamerole('德玛西亚之力', 10, 200) yasuo = Gamerole('疾风剑豪', 20, 80) dabaojian = Weapon('大宝剑', 20) dabaojian.weapon_attack(gailun, yasuo) # 但是这样不好,利用武器攻击也是人类是动作的发起者,所以不能是dabaojian对象发起 ------------------修改后如下------------------ # 修改代码 class Gamerole: def __init__(self, name, ad, hp): self.name = name self.ad = ad self.hp = hp def attack(self, p1): p1.hp -= self.ad print(f'{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血') def equip_weapon(self, wea): # 组合,给一个对象封装一个属性,该属性是另一个类的对象 self.wea = wea class Weapon: def __init__(self, name, ad): self.name = name self.ad = ad def weapon_attack(self, p1, p2): p2.hp = p2.hp - p1.ad - self.ad print(f'{p1.name}利用{self.name}攻击了{p2.name},{p2.name}还剩{p2.hp}血') # 实例化2个人物,1个武器 gailun = Gamerole('德玛西亚之力', 10, 200) yasuo = Gamerole('疾风剑豪', 20, 80) dabaojian = Weapon('大宝剑', 20) # 给人物装备上武器对象 gailun.equip_weapon(dabaojian) # 开始攻击 gailun.wea.weapon_attack(gailun, yasuo) # 攻击是以盖伦为主体的