在面向对象中,类和类之间也可以产生相关的关系
类中的关系: 依赖关系是最轻的,最重的是继承关系,关联关系是比较微妙的
依赖关系
执行某个动作的时候,需要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 = name
5 self.girFriend = girFriend
6 def play(self):
7 if self.girFriend:
8 print(f'{}带着他女朋友{self.girFriend.name}去吃饭')
9 else:
10 print('单身狗,还吃什么饭')
11 def movie(self):
12 if self.girFriend:
13 print(f'{}带着他女朋友{self.girFriend.name}去看电影')
14 else:
15 print('单身狗,还看什么电影')
16 class Girl:
17 def __init__(self,name):
18 = 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 = name
44 def work(self):
45 print(f'{}在上课')
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['人']='小明' #自动的调用__setitem__()
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 =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 = name
91 self.age = age
92 #这个对象字符串的表示
93 def __str__(self): #返回该对象的字符串表示形式
94 return f'{},{self.age}'
95 def __repr__(self): #该对象的官方的字符串表示形式
96 return f'{},{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 ------->
面向对象编程的执行流程
1.加载类 -> 给类创建一个名称空间 -> 主要存放类变量.
2.创建对象 -> 先找类. -> 根据类来开辟内存 -> 执行类中的__new__() -> 执行__init__() -> 返回对象