当一个类有多个实例,但是在实例之间有着相互的关联关系,此时,不建议在实例中新增一个成员属性来描述这种关联关系
据一个实际场景来帮助理解:People类有两个实例:AA和BB,AA是男的,BB 是女的,BB 是AA 的女朋友。它们之间有个情侣关系。
我想要描述这种人与人之间的情侣关系:那么,如果我采用的实现方法是向People类中添加一个成员属性lover_parterner。那么,会出现以下几个问题:
(1)如果一个人,他没有对象,那么这个属性的值如何初始化
----这个问题好解决,我们在成员属性中将lover_parterner的初始值设置为None就可以了
(2)现在假设这个人是有lover的,那么应该如何在初始化的时候就将lover_parterner属性的值赋为其lover这个实例呢?
----这是没有办法解决的事情。原因见下述代码
# A sample class example :
class People:
def __init__(self,pname,page,p_lover_parterner=None):
self.name = pname
self.age = page
self.lover_parterner = p_lover_parterner
def Info(self):
print(self.name,self.age,self.lover_parterner)
AA = People("AA",22,???) #此处按照逻辑,我本应该将 BB 实例作为函数的第三个参数,但,现在BB实例还没有被定义,无法作为参数赋值,尽管AA和BB已经是情侣关系
BB = People("BB",23,AA)
那有什么解决方法么?
有的,就是很麻烦:由于我们之前给单身的人们一条活路:将lover_parterner这个成员属性的初始值定为了None。所以现在,我们即使已知AA和BB 是情侣关系,我们依旧在实例化AA和BB 的时候,第三个参数不填写,使lover_parterner值为None。然后,用语句在后面显示地将这两个实例之间的lover_parterner属性值设为对方:
如下代码示:
# A sample class example :
class People:
def __init__(self,pname,page,p_lover_parterner=None):
self.name = pname
self.age = page
self.lover_parterner = p_lover_parterner
def Info(self):
print(self.name,self.age,"对象名字是:",self.lover_parterner.name)
AA = People("AA",22)
BB = People("BB",23)
AA.lover_parterner = BB #必须要双向绑定,AA绑定BB一次
BB.lover_parterner = AA #必须要双向绑定,BB绑定AA一次
AA.Info()
BB.Info()
这样就解决了。
但是这种解决方式,也引发了新的问题:试想一种情况,如果现在People的实例AA、BB、CC等多个人之间是同一个team的关系。那么,此时,难道要再设立一个数据结构为列表的 team_parterner 成员属性,每次这个team新来一个新人,之前的老人儿就都将自己的team_parterner 进行增加:把这个新人加入到自己的team_parterner列表中去么?这样一来是操作繁琐(大量的重复劳动),二来是:万一哪个 老人儿 漏掉了谁没有添加进自己的列表,这种就会造成不一致。
那么如何解决这种 同类实例 之间的 关联关系 呢 ?
---- 新建立一个类,用这个类生成的实例来维护同类实例之间的关联关系
假设AA、BB是新人 , AA要拜师MM,即加入MM队伍 ; BB要拜师NN,即加入NN队伍 ; CC、DD要拜师BB,即加入BB队伍。现假设现在队伍中就只有MM。
那么实现代码如下:
# A sample class example :
class People:
def __init__(self,pname,page):
self.name = pname
self.age = page
def Info(self):
print(self.name,self.age)
class Team_Relation:
def __init__(self):
self.team_list = []
def insert_new_people( self , new_peo_obj , old_peo_obj):
tag = 0
for team_item in self.team_list :
if old_peo_obj in team_item :
tag = 1
team_item.append(new_peo_obj)
print("此时的情况是新人",new_peo_obj.name,"找到了队伍成功加入老同志",old_peo_obj.name,"所在的队伍")
if tag==0:
newteam = [new_peo_obj,old_peo_obj]
self.team_list.append(newteam)
print("此时的情况是新人",new_peo_obj.name,"发现老同志",old_peo_obj.name,"不属于任何队伍,于是他俩自己组成了一个新队伍")
def team_Info(self):
for team_item in self.team_list:
print( [ peo_obj.name for peo_obj in team_item ] ) ## [ peo_obj.name for peo_obj in team_item ] 是一种叫列表解析式的语法糖
# 假设AA、BB是新人 , AA要拜师MM,即加入MM队伍 ; BB要拜师NN,即加入NN队伍 ; CC、DD要拜师BB,即加入BB队伍
# 假设现在队伍中就只有MM
AA = People("AA",22)
BB = People("BB",23)
CC = People("CC",21)
DD = People("DD",26)
MM = People("MM",22)
NN = People("NN",23)
team_relation_set = Team_Relation()
team_relation_set.team_list.append([MM]) # 对应实现假设:现在队伍中就只有MM,他自成一个team
team_relation_set.insert_new_people(AA,MM)
print('--'*50)
team_relation_set.insert_new_people(BB,NN)
print('--'*50)
team_relation_set.insert_new_people(CC,BB)
print('--'*50)
team_relation_set.insert_new_people(DD,BB)
但没完,确实不再需要冗余的的处理了对于同项目组的人员添加了,但是,当我想通过一个people实例来去查询自己属于那个组,组里还有哪些人的时候,这种时候,上述的代码就不能做得到。
解决办法是:将关系类Team_Relation的实例 team_realtion_obj 作为People类中的一个成员属性
即:
# A sample class example :
class People:
def __init__(self,pname,page,team_relation_obj):
self.name = pname
self.age = page
self.team_relation = team_relation_obj
def Info(self):
print(self.name,self.age)
class Team_Relation:
def __init__(self):
self.team_list = []
def insert_new_people( self , new_peo_obj , old_peo_obj):
tag = 0
for item_team in self.team_list :
if old_peo_obj in item_team :
tag = 1
item_team.append(new_peo_obj)
print("此时的情况是新人",new_peo_obj.name,"找到了队伍成功加入老同志",old_peo_obj.name,"所在的队伍")
if tag==0:
newteam = [new_peo_obj,old_peo_obj]
self.team_list.append(newteam)
print("此时的情况是新人",new_peo_obj.name,"发现老同志",old_peo_obj.name,"不属于任何队伍,于是他俩自己组成了一个新队伍")
def team_Info(self):
"""将所有的team他们中的成员全部输出"""
for item_team in self.team_list:
print( [ peo_obj.name for peo_obj in item_team ] ) ## [ peo_obj.name for peo_obj in team_item ] 是一种叫列表解析式的语法糖
def judge_people_in_which_team(self,peo_obj):
"""判断peo_obj是在哪个team中,并打印team的信息"""
tag = 0
for item_team in self.team_list :
if peo_obj in item_team :
print(peo_obj.name,"属于一个team中,该team的成员有:",[peo_item.name for peo_item in item_team] )
tag = 1
break
if tag == 0 :
print("这个人不在任何的项目组中阿")
# 假设AA、BB是新人 , AA要拜师MM,即加入MM队伍 ; BB要拜师NN,即加入NN队伍 ; CC、DD要拜师BB,即加入BB队伍
# 假设现在队伍中就只有MM
team_relation_set = Team_Relation() # 那么这个时候就得先对关系进行实例化了
AA = People("AA",22,team_relation_set)
BB = People("BB",23,team_relation_set)
CC = People("CC",21,team_relation_set)
DD = People("DD",26,team_relation_set)
MM = People("MM",22,team_relation_set)
NN = People("NN",23,team_relation_set)
qqqqq = People("qqqqq",26,team_relation_set)
# --------------------------------------------------------------------------
team_relation_set.team_list.append([MM]) # 对应实现假设:现在队伍中就只有MM
team_relation_set.insert_new_people(AA,MM)
team_relation_set.insert_new_people(BB,NN)
team_relation_set.insert_new_people(CC,BB)
team_relation_set.insert_new_people(DD,BB)
print('--'*50)
# --------------------------------------------------------------------------
AA.team_relation.judge_people_in_which_team(AA)
CC.team_relation.judge_people_in_which_team(CC)
qqqqq.team_relation.judge_people_in_which_team(qqqqq)
上述代码有两个要点要注意:
首先是,由于People类实例化时需要Team_Realtion的实例作为参数,那么肯定得先对关系进行实例化了。
其次是,对于从People实例中去判断该实例是否属于team等 需要通过People实例 对 关系 进行操作 的函数 一般放在关系类中进行定义(比如本例中的
judge_people_in_which_team() 这个函数在类Team_Realtion定义 )
【Note】这里补充一个可能存在的疑问:为啥代码里AA.team_relation.judge_people_in_which_team(AA) 明明是AA实例调用,但还要传个参数 AA呢?
因为:AA调用的是team_relation这个类属性(这个 AA 的 team_relation 类属性呢又是一个Team_Realtion实例)。然后,Team_Realtion实例去调用定义在Team_Realtion类中的函数,那这肯定需要传入参数peo_obj呀,毕竟这个函数是Team_Realtion类中的函数