python类与类之间的关系
在面向对象中,类和类之间也可以产生相关的关系
类中的关系: 依赖关系是最轻的,最重的是继承关系,关联关系是比较微妙的
依赖关系
执行某个动作的时候,需要xxx来帮助完成这个操作,此时的关系是最轻的.
随时可以更换另外一个东西来完成此操作
1 class Person: 2 def f1(self,tools): # 通过参数的传递把另外一个类的对象传递进来 3 tools.run() 4 print('皮一下很开心') 5 class Computer: 6 def run(self): 7 print('电脑开机运行') 8 class Phone: 9 def run(self): 10 print('手机开机') 11 c = Computer() 12 a = Phone() 13 p = Person() 14 p.f1(a) #把Phone类的对象a传递给Person的f1方法作为参数 15 结果 16 手机开机 17 皮一下很开心 18 19 事例二 20 植物大战僵尸 21 class Plant: 22 def __init__(self,hp,ad): 23 self.hp = hp 24 self.ad = ad 25 def attack(self,js): 26 print('植物攻击僵尸') 27 js.hp -= self.ad 28 print(f'僵尸掉血{self.ad},剩余{js.hp}') 29 class JiangShi: 30 def __init__(self,hp,ad): 31 self.hp = hp 32 self.ad = ad 33 def attack(self,zw): 34 print('僵尸咬植物') 35 zw.hp -= self.ad 36 print(f'植物掉血{self.ad},剩余{zw.hp}') 37 zw = Plant(100,11) 38 js = JiangShi(80,15) 39 zw.attack(js) 40 zw.attack(js) 41 js.attack(zw) 42 js.attack(zw) 43 结果 44 植物攻击僵尸 45 僵尸掉血11,剩余69 46 植物攻击僵尸 47 僵尸掉血11,剩余58 48 僵尸咬植物 49 植物掉血15,剩余85 50 僵尸咬植物 51 植物掉血15,剩余70
关联关系
对象里面包含对象
1 一对一关系 2 class Boy: 3 def __init__(self,name,girFriend=None): 4 self.name = name 5 self.girFriend = girFriend 6 def play(self): 7 if self.girFriend: 8 print(f'{self.name}带着他女朋友{self.girFriend.name}去吃饭') 9 else: 10 print('单身狗,还吃什么饭') 11 def movie(self): 12 if self.girFriend: 13 print(f'{self.name}带着他女朋友{self.girFriend.name}去看电影') 14 else: 15 print('单身狗,还看什么电影') 16 class Girl: 17 def __init__(self,name): 18 self.name = name 19 b = Boy('刘昊然') 20 g = Girl('刘丽') 21 b.play() 22 23 b.girFriend = g 24 b.play() 25 26 g2 = Girl('王萌') 27 b.girFriend = g2 28 b.movie() 29 30 31 一对多关系 32 self.teach_list = [t1,t2,...] 33 class School: 34 def __init__(self,name): 35 self.teach_list = [] 36 def zhaopin(self,teach): 37 self.teach_list.append(teach) 38 def shangke(self): 39 for i in self.teach_list: 40 i.work() 41 class Teacher: 42 def __init__(self,name): 43 self.name = name 44 def work(self): 45 print(f'{self.name}在上课') 46 lnh = School('测试') 47 t1 = Teacher('赵老师') 48 t2 = Teacher('刘老师') 49 lnh.zhaopin(t1) 50 lnh.zhaopin(t2) 51 lnh.shangke() 52 结果 53 赵老师在上课 54 刘老师在上课
继承关系
1 class Base: #父类又叫基类又叫超类 2 def chi(self): 3 print('吃饭') 4 class Foo(Base): #子类又叫派生类,这个类继承了Base类,Foo类是对Base的一个扩展 5 def he(self): 6 print('喝水') 7 f = Foo() 8 f.chi() 9 f.he() 10 print(hash(Foo)) #默认类和创建的对象都是可哈希的 11 print(hash(Foo())) 12 结果 13 吃饭 14 喝水 15 -9223371912599947772 16 -9223371912597968945 17 18 去掉可哈希 19 __hash__ = None 20 class Base: 21 def chi(self): 22 print('吃饭') 23 class Foo(Base): 24 __hash__ = None # 当前类的对象不可哈希 25 def he(self): 26 print('喝水') 27 f = Foo() 28 f.chi() 29 f.he() 30 print(hash(Foo)) # 类名永远可哈希 31 print(hash(Foo())) # TypeError: unhashable type: 'Foo'
类名相当于变量名
1 class Foo: 2 def chi(self,food): 3 print('吃鱼和',food) 4 class Bar: 5 def chi(self,food): 6 print('吃肉和',food) 7 dic = {Foo:'面包',Bar:'牛奶'} 8 for k,v in dic.items(): 9 k().chi(v) 10 结果 11 吃鱼和 面包 12 吃肉和 牛奶
练习
1 事例1 2 class Base: 3 def __init__(self, num): 4 self.num = num 5 6 def func1(self): 7 print(self.num) 8 self.func2() 9 10 def func2(self): 11 print(111, self.num) 12 13 class Foo(Base): 14 def func2(self): 15 print(222, self.num) 16 17 lst = [Base(1), Base(2), Foo(3)] 18 for obj in lst: 19 obj.func2() 20 结果 21 111 1 22 111 2 23 222 3 24 25 事例2 26 class Base: 27 def __init__(self, num): 28 self.num = num 29 def func1(self): 30 print(self.num) 31 self.func2() 32 def func2(self): 33 print(111, self.num) 34 35 class Foo(Base): 36 def func2(self): 37 print(222, self.num) 38 39 lst = [Base(1), Base(2), Foo(3)] 40 for obj in lst: 41 obj.func1() 42 结果 43 1 44 111 1 45 2 46 111 2 47 3 48 222 3
self:谁调用的就是谁,类型是根据调用方的对象来进行变换的
super:表示的是父类
特殊成员:
__init__() # 创建对象的时候初始化操作
__call__() # 对象()
__getitem__() # 对象[哈哈]
__setitem__() # 对象[哈哈] = 值
__new__() # 创建对象的时候.开辟内存
__hash__() # 可哈希 hash()
1 __call__ 2 对象后面加括号,触发执行 3 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()() 4 class Foo: 5 def __init__(self): 6 pass 7 8 def __call__(self, *args, **kwargs): 9 print('__call__') 10 11 obj = Foo() # 执行 __init__ 12 obj() # 执行 __call__ 13 结果 14 __call__ 15 16 事例2 17 class Foo: 18 def __init__(self): # 初始化操作 19 print('我是init,我是第二') 20 21 def __new__(cls, *args, **kwargs): # 创建,是真正的构造方法,可以开辟内存 22 print('我是new,我是第一') 23 return object.__new__(cls) 24 25 def __call__(self, *args, **kwargs): # 对象() 26 print('我是对象call') 27 28 def __getitem__(self, item): # 对象[] 29 print('item',item) 30 print('我是getite') 31 32 def __setitem__(self, key, value): # 对象[key] = value 33 print('key',key) 34 print('value',value) 35 Foo() 36 f = Foo() # 自动执行__init__() 37 f() # 调用__call__() 38 print(callable(f)) # 对象() 39 print(f['娃哈哈']) #自动调用__getitem__() 40 f['人']='刘丽' #自动的调用__getitem__() 41 结果 42 我是new,我是第一 43 我是init,我是第二 44 我是new,我是第一 45 我是init,我是第二 46 我是对象call 47 True 48 item 娃哈哈 49 我是getite 50 None 51 key 人 52 value 刘丽 53 54 55 事例3 56 class Foo: 57 def __init__(self,name): 58 self.name=name 59 60 def __getitem__(self, item): 61 print(self.__dict__[item]) 62 63 def __setitem__(self, key, value): 64 self.__dict__[key]=value 65 def __delitem__(self, key): 66 print('del obj[key]时,我执行') 67 self.__dict__.pop(key) 68 def __delattr__(self, item): 69 print('del obj.key时,我执行') 70 self.__dict__.pop(item) 71 72 f1=Foo('sb') 73 f1['age']=18 74 f1['age1']=19 75 print(f1.__dict__) 76 del f1.age1 77 del f1['age'] 78 f1['name']='alex' 79 print(f1.__dict__) 80 结果 81 {'name': 'sb', 'age': 18, 'age1': 19} 82 del obj.key时,我执行 83 del obj[key]时,我执行 84 {'name': 'alex'} 85 86 87 事例4 88 class Person: 89 def __init__(self,name,age): 90 self.name = name 91 self.age = age 92 #这个对象字符串的表示 93 def __str__(self): #返回该对象的字符串表示形式 94 return f'{self.name},{self.age}' 95 def __repr__(self): #该对象的官方的字符串表示形式 96 return f'{self.name},{self.age}' 97 s = Person('bob','18') 98 print(s) 99 结果 100 bob,18 101 102 事例5 103 class B: 104 def __str__(self): 105 return 'str : class B' 106 def __repr__(self): 107 return 'repr : class B' 108 b = B() 109 print('%s' % b) #这个执行的是__str__函数方法 110 print('%r' % b) #这个执行的是__repr__函数方法 111 结果 112 str : class B 113 repr : class B 114 115 116 __del__ 117 析构方法,当对象在内存中被释放时,自动触发执行 118 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。 119 class Foo: 120 121 def __del__(self): 122 print('执行我啦') 123 124 f1=Foo() 125 del f1 126 print('------->') 127 结果 128 执行我啦 129 ------->