一.今日主要内容:
1.类与类之间的关系
在我们的世界中事物和事物之间总会有一些联系.
在面向对象中,类和类之间也可以产生相关的关系
(1)依赖关系
执行某个动作(方法)的时候,需要xxx来帮助你完成这个操作,此时的关系是最轻的.
随时可以更换另外一个东西来完成此操作
大象进冰箱&植物大战僵尸
(2)关联关系(在对象里面埋对象)
老师=>学校
A.一对一关系 self.girlFriend=girl
典型案例:你和你的女朋友
B.一对多关系(生活中,更多的是这种关系) self.teach_list=[t1,t2,t3]
一个学校,一堆老师
C.多对多关系
类中的关系:依赖关系最轻的,最重的是继承关系,关联关系是比较微妙的.
2.self到底是谁?
self:谁调用的就是谁.类型是根据调用方的对象来进行变换的(不一定是这个类)
super:与继承相关的.(表示的是父类)
3.关联关系=>组合=>聚合=>UML图(一看就会清晰明了了)(类与类之间的关系UML图)
4.特殊成员:(我们没有主动调用,而是自动调用)
__init__() #创建对象的时候初始化操作
__new__() #创建对象的时候,开辟内存
__call__() #对象()
__getitem__() #对象['冬瓜']
__setitem__() #对象['冬瓜']=值
__hash__() #可哈希 hash()
__enter__() #with 对象
__exit__() #结束with的时候
class A:
def __init__(self):
xxxx
a=A()
二.今日内容大纲:
1.依赖关系
2.关联关系
3.继承关系
4.特殊成员
三.今日内容详解:
1.依赖关系
(1)依赖关系例题
class Person: def play(self,tools): #通过参数的传递把另外一个类的对象传递进来 tools.run() print('很开心,我能玩儿游戏了') class Computer(): def run(self): print('电脑开机,可以运行') class Phone(): def run(self): print('手机开机,可以运行了') c=Computer() phone=Phone() p=Person() p.play(phone)
(2)
#典型的依赖关系,可以像方法进行缩进优化(思考)
#这个题目还是有一定的深度的,在攻击力里边的写法
#写一个植物大战僵尸
# 1.植物
# 打僵尸,将是掉血
# 2.僵尸
# 吃植物,植物掉血
#自己写的版本,漏洞很多,思考的灵活性还是不够 class plant(): def __init__(self,name,blood,gjl): self.name=name self.blood=blood self.gjl=gjl def skill(self,js): js.blood-=self.gjl print(f'僵尸掉血{self.gjl},还剩下{js.blood}') class jiangshi(): def __init__(self,name,blood,gjl): self.name=name self.blood=blood self.gjl=gjl def j_skill(self,zw): zw.blood-=self.gjl print(f'植物掉血{self.gjl},还剩下{zw.blood}') zhiwu=plant('大冬瓜',100,1) js=jiangshi('小僵尸',20,2) zhiwu.skill(js) js.j_skill(zhiwu) # pjf=pj_fight() # pjf.play(zhiwu) #老师讲解 class plant(): def __init__(self,name,hp,ad): self.name = name self.hp = hp self.ad = ad def attack(self,js): #注意这里需要名字js print('植物攻击僵尸') js.hp-=self.ad print(f'僵尸掉血{self.ad},还剩下{js.hp}') class jiangshi(): def __init__(self,name,hp,ad): self.name = name self.hp = hp self.ad = ad def attack(self,zw): print('僵尸咬植物') zw.hp-=self.ad print(f"植物掉血{self.ad},还剩{zw.hp}") wd = plant('大冬瓜', 100, 1) js = jiangshi('小僵尸', 20, 2) wd.attack(js) wd.attack(js) wd.attack(js) js.attack(wd) js.attack(wd) js.attack(wd) js.attack(wd) #人狗大战&西门庆与武松大战都可以写了
2.关联关系
(1)一对一关系
class Boy: def __init__(self,name,girlFriend=None): #在初始化的时候可以给一个对象的属性设置成另一个 类的对象 self.name=name self.girlFriend=girlFriend #一个男孩有一个女朋友 def chi(self): if self.girlFriend: print(f'带着他的女朋友{self.girlFriend.name}去吃饭') else: print('单身狗,吃什么吃?滚去学习') def movie(self): if self.girlFriend: print(f'带着他的女朋友{self.girlFriend.name}去看电影') else: print('单身狗,吃什么吃?滚去学习') class Girl: def __init__(self,name): self.name=name #第一步 b=Boy('宝浪') g=Girl('孙艺珍') b.chi() #第二步 #alex给宝浪介绍了一个女朋友,孙艺珍 b=Boy('宝浪') g=Girl('孙艺珍') b.girlFriend=g b.chi() #第三步 b=Boy('宝浪') g=Girl('孙艺珍') g2=Girl('梁咏琪') #在这里换了女朋友 b.girlFriend=g2 #换了个女朋友 b.chi()
(2)
#一对多关系(使用率最高的关系),超级重点
#这个通过列表的创建,列表的添加,for循环列表
#与 初始化,招聘老师,上课老师 进行方法对应
class School(): def __init__(self,name): self.teach_list=[] #这里要装多个老师 #注意这里搞了一个列表 #创建 self.name=name self.hehe='呵呵' #初始化时候,可以给一些属性 def zhaopin(self,teach): #添加 self.teach_list.append(teach) def shangke(self): for t in self.teach_list: #循环执行 t.work() class Teacher: def __init__(self,name): self.name=name def work(self): print(f'{self.name}在上课') lnh=School('老男孩') t1=Teacher('武sir') t2=Teacher('太白') t3=Teacher('哪吒') t4=Teacher('女神') t5=Teacher('日天') t6=Teacher('宝浪') lnh.zhaopin(t1) #在这个地方添加的是实例化后的对象 lnh.zhaopin(t2) lnh.zhaopin(t3) lnh.zhaopin(t4) lnh.zhaopin(t5) lnh.zhaopin(t6) lnh.shangke() #一执行,就把上边的全部执行了 #因为上课中用到的是for遍历列表中的细信息
3.继承关系
(1)
class Base: def chi(self): print('我会吃') #派生类=>就是子类 class Foo(Base): #这个类继承了Base类,Foo类是对Base的一个扩展 def he(self): print('我会喝') f=Foo() f.chi() f.he()
(2)
#注意名称的描述 class Cat: #父类=>基类(超类) def catch_mouse(self): print("猫可以抓老鼠") class BosiCat(Cat): #子类=>派生类 pass
(3)
class Foo: pass print(hash(Foo)) #可哈希 print(hash(Foo())) #可哈希 #总结:我们写好的类和创建的对象默认都是可哈希的 class Foo: __hash__=None print(hash(Foo)) #可哈希 print(hash(Foo())) #unhashable type: 'Foo' #类永远是可哈希的,但是加上__hash__=None, # 对象就不可哈希了
(4)
#利用字典进行调用 class Foo: def chi(self): print('我爱吃鱼') class Bar: def chi(self): print('我爱吃肉') dic ={Foo:Foo(),Bar:Bar()} for k,v in dic.items(): v.chi()
(5)
#利用字典调用=>升级 class Foo: def chi(self,food): print('我爱吃鱼和',food) class Bar: def chi(self,food): print('我爱吃肉和',food) dic ={Foo:'鸡蛋',Bar:'香肠'} for k,v in dic.items(): k().chi(v)
(6)self系列
# self中 先找自己的,再找父类的 #对比函数进行回顾: # 类名 => 变量名 ->相同的道理 # def func(): # pass # # an = func # an()
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) class Foo(Base): pass obj = Foo(123) obj.func1() ''' 结果: 123 '''
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) class Foo(Base): def func1(self): print("Foo. func1", self.num) obj = Foo(123) obj.func1() ''' 结果: Foo. func1 123 '''
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) self.func2() def func2(self): print("Base.func2") class Foo(Base): def func2(self): print("Foo.func2") obj = Foo(123) obj.func1() ''' 结果: 123 Foo.func2 '''
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) self.func2() def func2(self): print(111, self.num) class Foo(Base): def func2(self): print(222, self.num) lst = [Base(1), Base(2), Foo(3)] for obj in lst: obj.func2() ''' 结果: 111 1 111 2 222 3 '''
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) self.func2() def func2(self): print(111, self.num) class Foo(Base): def func2(self): print(222, self.num) lst = [Base(1), Base(2), Foo(3)] for obj in lst: obj.func1() ''' 结果: 1 111 1 2 111 2 3 222 3 '''
4.特殊成员
(1)
class Foo: def __init__(self): print('初始化操作,在创建对象的时候自动调用这个方法') f=Foo() #自动执行__init__() f.__init__() #第一次这么写,以后不要这么写 #上边两行是等价的
(2)
# 回顾:三大器1 # lst=[] # lst.__iter__() #回顾内置函数 # lst=[1,2,3,4] # it=iter(lst) # print(it.__next__()) # print(next(it))
(3)
#callable 可调用的 判断xxx是否是可调用的 # 曾经的例子: # def func(): # pass # print(callable(func)) # func=3 # print(callable(func)) #此时变成不可调用的 # class Foo: # def __init__(self): # print('初始化操作,在创建对象的时候自动调用这个方法') # f=Foo() #结果:初始化操作,在创建对象的时候自动调用这个方法 # print(callable(f)) #False 说明对象不可调用 # #__call__()的作用: # class Foo: # def __init__(self): # print('初始化操作,在创建对象的时候自动调用这个方法') # # #为了对象能够被调用而生的 f() # def __call__(self, *args, **kwargs): # print('我是对象()') # f=Foo() #初始化操作,在创建对象的时候自动调用这个方法 # f() #我是对象(), 调用的是__call__内的东西 # print(callable(f)) #True
(4)
#__getitem__ 字典,元组,列表都是用的这个 (给值) # class Foo: # #对象[] # def __getitem__(self, item): # print('item=',item) # print('你执行了__getitem__') # return '哈哈' # f=Foo() #初始化操作,在创建对象的时候自动调用这个方法 # print(f['李嘉诚']) ''' 结果: item= 李嘉诚 你执行了__getitem__ 哈哈 '''
(5)
#__setItem__()方法 # class Foo: # def __setitem__(self, key, value): # print("key, ", key) # print("value, ", value) # f=Foo() # f['jay'] = "林俊杰" ''' 结果: key, jay value, 林俊杰 '''
(6)
# __delitem__()方法 # class Foo: # def __delitem__(self, key): # print('key=',key) # f=Foo() # del f['哈哈'] ''' 结果: key= 哈哈 '''
(7)
# __enter__() 方法 #__exit__()方法 # class Foo: # # with 对象: # def __enter__(self): # print("我是enter") # # with 对象: 代码执行完毕. 最后执行这里 # def __exit__(self, exc_type, exc_val, exc_tb): # print("我叫exit") # f=Foo() # with f: # print("我是哈哈哈哈") ''' 结果: 我是enter 我是哈哈哈哈 我叫exit '''
(8)
# class Foo: # def __init__(self): # 初始化操作 # print("我是init, 我是老二") # print("初始化操作. 在创建对象的时候自动调用这个方法") # # def __new__(cls, *args, **kwargs): # 创建, 它是真正的构造方法, 可以开辟内存 # print("我是new. 我是老大") #在开辟内存之前可以放东西 # return object.__new__(cls)
(9)
# lst = ["孙艺珍", "李金珠", "井柏然"] # # lst[2] # =>自动的调用__getitem__()
(10)
面向对象编程的执行流程=>
1.加载类=>给类创建一个名称空间=>主要存放类变量
2.创建对象=>先找类=>根据类来开辟内存=>
执行类中的__new__() -> 执行__init__() -> 返回对象
(11)
#__str__() and __repr__() class Student: def __init__(self,name,no,gender,cls,age): self.name=name self.no=no self.gender=gender self.cls=cls self.age=age # 遇到出不来,两个都尝试一下 # 如果只是内存地址,再写另一个试试 #这个对象字符串的表示 # def __str__(self): #返回该对象的字符串表示形式 # return f'{self.name},{self.no},{self.gender}' # def __repr__(self): #该对象的官方的字符串表示形式 # return f'{self.name},{self.no},{self.gender}' s = Student("冬瓜", "3", "男", "S18", "31") print(s)
作业讲解:记得补充: