(十七)类与类之间的关系
Posted asia-yang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(十七)类与类之间的关系相关的知识,希望对你有一定的参考价值。
?. 类与类之间的依赖关系
?千世界, 万物之间皆有规则和规律。我们的类和对象是对?千世界中的所有事物进?归类, 那事物之间存在着相对应的关系。 类与类之间也同样如此,在?向对象的世界中 类与类中存在以下关系:
1. 依赖关系
2. 关联关系
3. 组合关系
4. 聚合关系
5. 继承关系
6. 实现关系
先来看紧密程度最低的?个----依赖关系。假设要玩游戏,那么使用什么呢?现在的方式挺多的,手机电脑,PS等,都可以,但是如果没有这些工具,就玩不了这样的游戏,所以玩游戏又得依赖这些工具,但是我可以选择使用哪种工具,一种玩够了,可以换别的工具继续玩。看代码:
class Phone: def __init__(self): self.name = ‘手机‘ class Computer: def __init__(self): self.name = ‘电脑‘ class PS: def __init__(self): self.name = ‘PS‘ class Person: def play(self, type): print(f‘使用{type.name}打游戏‘) phone = Phone() computer = Computer() ps = PS() p = Person() p.play(phone) p.play(computer) p.play(ps)
可以看到,人玩游戏时,是可以随便更换工具的,所以这种依赖关系很不稳定,也就是紧密程度很低。
?. 关联关系.组合关系, 聚合关系
其实这三个在代码上写法是?样的,但是从含义上是不?样的。
1. 关联关系: 两种事物必须是互相关联的,但是在某些特殊情况下是可以更改和更换的。
2. 聚合关系:属于关联关系中的?种特例,侧重点是xxx和xxx聚合成xxx。各?有各?的生命周期,比如电脑,电脑?有CPU, 硬盘, 内存等等。电脑挂了,CPU还是好的,还是完整的个体。
3. 组合关系:属于关联关系中的?种特例,写法上差不多,组合关系比聚合还要紧密,比如?的?脑, ?脏, 各个器官。这些器官组合成?个?,这时?如果挂了,其他的东?也跟着挂了。
?先我们看关联关系: 这个最简单,也是最常?的?种关系。比如,?家都有男女朋友,男?关联着女朋友,女?关联着男朋友,这种关系可以是互相的,也可以是单??的。
class Boy: def __init__(self, name, girlFriend=None): self.name = name self.girlFriend = girlFriend def have_a_dinner(self): if self.girlFriend: print("%s 和 %s?起去吃晚餐" % (self.name, self.girlFriend.name)) else: print("单身狗. 吃什么饭") class Girl: def __init__(self, name): self.name = name b = Boy("jerry") b.have_a_dinner() # 突然?B了. 找到?朋友了 g = Girl("如花") b.girlFriend = g # 有?朋友了 b.have_a_dinner() gg = Girl("李?花") bb = Boy("tom", gg) # 娃娃亲. 出?就有?朋友. 服不服 bb.have_a_dinner() # 多么幸福的?家 # 突然.bb失恋了. 娃娃亲不跟他好了 bb.girlFriend = None bb.have_a_dinner() # ?单身了
注意:此时Boy和Girl两个类之间就是关联关系,两个类的对象紧密练习着。其中?个没有了,另?个就孤单的不得了,关联关系, 其实就是我需要你,你也属于我。这就是关联关系。像这样的关系有很多很多, 比如,学校和老师之间的关系。
School --- 学校
Teacher--- 老师
老师必然属于?个学校,换句话说,每个老师肯定有?个指定的?作机构, 就是学校,那老师的属性中必然关联着学校。
class School: def __init__(self, name, address): self.name = name self.address = address class Teacher: def __init__(self, name, school=None): self.name = name self.school = school s1 = School("北京大学", "地址111111") s2 = School("清华大学", "地址222222") s3 = School("哈佛大学", "地址333333") t1 = Teacher("Tom", s1) t2 = Teacher("Jerry", s1) t3 = Teacher("Tony", s2) t4 = Teacher("Peter", s3) # 找到Peter所在的校区地址 print(t4.school.address)
想想,这样的关系如果反过来,?个老师可以选?个学校任职。那反过来,?个学校有多少老师呢? ?堆吧? 这样的关系如何来描述呢?
class School: def __init__(self, name, address): self.name = name self.address = address self.t_list = [] # 每个学校都应该有?个装?堆?师的列表 def add_teacher(self, teacher): self.t_list.append(teacher) class Teacher: def __init__(self, name, school=None): self.name = name self.school = school s1 = School("北京大学", "地址111111") s2 = School("清华大学", "地址222222") s3 = School("哈佛大学", "地址333333") t1 = Teacher("Tom", s1) t2 = Teacher("Jerry", s1) t3 = Teacher("Tony", s2) t4 = Teacher("Peter", s3) s1.add_teacher(t1) s1.add_teacher(t2) s1.add_teacher(t3) # 查看北京大学有哪些?师 for t in s1.t_list: print(t.name)
好了,这就是关联关系。 当我们在逻辑上出现了,我需要你,你还得属于我。这种逻辑就是关联关系,那注意,这种关系的紧密程度比上?的依赖关系要紧密的多。为什么呢? 老师没有学校,就不能教书了,学校没有了老师,就没有老师教学生了。两者是互相需要的,学校需要老师,而且这个老师也是属于这个学校的。开始的依赖关系中,我玩游戏,不用手机,还可以使用其他的电脑或者PS等。
?于组合关系和聚合关系,其实代码上的差别不?,都是把另?个类的对象作为这个类的属性来传递和保存,只是在含义上会有些许的不同?已。
三. 继承关系.
在?向对象的世界中存在着继承关系,我们现实中也存在着这样的关系,我们说过。 x是?种y,那x就可以继承y,这是理解层?上的。如果上升到代码层?,我们可以这样认为?类在不影响?类的程序运?的基础上对?类进?的扩充和扩展。这?,我们可以把?类被称为超类或者基类,?类被称为派?类。
?先, 类名和对象默认是可以作为字典的key的。
class Foo: def __init__(self): pass def method(self): pass # __hash__ = None print(hash(Foo)) print(hash(Foo())) 既然可以hash. 那就是说字典的key可以是对象或者类。虽然显?的有点?诡异. 但是是可以?的。 dic = {} dic[Foo] = 123 dic[Foo()] = 456 print(dic) # {<class ‘__main__.Foo‘>: 123, <__main__.Foo object at 0x103491550>: 456}
接下来,我们来继续研究继承上的相关内容。在此主要研究?下self,记住不管?法之间如何进?调?,类与类之间是何关系,默认的self都是访问这个?法的对象。
分析一下上面的代码:1号线表示初始化时,把值=123给了num;2号线表示obj调用func1(),但是在类Foo中没有这个方法,所以程序会去Foo的父类Base中查找,OK,找到了,同时把obj传递给了self。在func1()里打印完num的值后,又调用了func2(),谁调用的这个func2()呢?当然是self,这里的self,又是func1()被调用时,传递进来的obj,也就是Foo的对象,所以,要找func2(),也得去Foo中找,这是就近原则,也就是3号线的方向,虽然这样看起来是跑远了,但是Python就是这样规定的。很完美找到了,所以直接打印就好了。看看下面代码,自己玩玩吧。
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() # 那笔来吧. 算好了,可以跑一遍,看看结果。
四. 类中的特殊成员
什么是特殊成员呢? __init_()就是?个特殊的成员,说?了带双下划线的那些, 这些?法在特殊的场景的时候会被?动的执?。 比如:
1. 类名() 会?动执?__init__()
2. 对象() 会?动执?__call__()
3. 对象[key] 会?动执?__getitem__()
4. 对象[key] = value 会?动执?__setitemm__()
5. del 对象[key] 会?动执? __delitem__()
6. 对象+对象 会?动执? __add__()
7. with 对象 as 变量 会?动执?__enter__ 和__exit__
8. 打印对象的时候 会?动执? __str__
9. ?掉可哈希 __hash__ == None 对象就不可哈希了.
创建对象的真正步骤:
?先, 在执?类名()的时候,系统会?动先执?__new__()来开辟内存,此时新开辟出来的内存区域是空的。紧随其后, 系统?动调?__init__()来完成对象的初始化?作,按照时间轴来算。
1. 加载类
2. 开辟内存(__new__)
3. 初始化(__init__)
4. 使?对象调用变量或者方法
以上是关于(十七)类与类之间的关系的主要内容,如果未能解决你的问题,请参考以下文章