文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Python的弱引用

2023-01-31 07:02

关注

python的弱引用指引用一个对象但不增加它的引用计数器。这么做的好处是什么呢?什么时候需要考虑用若引用呢?

假设我们在设计一个游戏,有一个角色类Char,我们要给他添加一个效果(比如中毒),于是设计了一个效果类Effect。现在,给角色增加效果看上去就像这样:

  1. char.effect = Effect() # 给角色添加一个效果

每个效果生效的时机都是不同的,为了方便复用,我们再设计一个激活策略类ActivePloy,负责激活效果。于是在Effect和ActivePloy的内部看上去就像这样:

  1. class Effect(object):   
  2.     def __init__(self):   
  3.         self.active_ploy = ActivePloy(self) 
  4.  
  5.     def active(self): 
  6.         """激活时的处理""" 
  7.         pass 
  8.  
  9.  
  10. class ActivePloy(object): 
  11.     def __init__(self, effect): 
  12.         self.effect = effect 
  13.  
  14.     def active(self): 
  15.         """激活时,激活对应效果""" 
  16.         self.effect.active() 

这样做的好处是Effect不用关心自己何时激活,激活的判断都放给ActivePloy来处理。看上去挺好的,但是,这里面有一个问题,就是当我们试图给玩家去掉这个效果时……

  1. del char.effect 

仔细想想,这么干以后,Effect的实例其实是没有被回收的,因为Effect和ActivePloy交叉引用,他们的引用计数都为1。

那么我们为了干净的删除effect,似乎就只能手动的来清理一下他们之间的这个交叉引用了:

  1. class Effect(object):    
  2.     def __init__(self):    
  3.         self.active_ploy = ActivePloy(self)  
  4.   
  5.     def active(self):  
  6.         """激活时的处理"""  
  7.         pass  
  8.   
  9.     def destroy(self): 
  10.         self.active_ploy.destroy() 
  11.   
  12. class ActivePloy(object):  
  13.     def __init__(self, effect):  
  14.         self.effect = effect  
  15.   
  16.     def active(self):  
  17.         """激活时,激活对应效果"""  
  18.         self.effect.active() 
  19.  
  20.     def destroy(self): 
  21.         self.effect = None 

于是我们要删除一个效果,就得这样:

  1. char.effect.destroy() 
  2. del char.effect 

太麻烦了,不是吗?而且万一一个效果有多个激活策略的话,必须保证Effect把每个ActivePloy的destroy方法都运行一遍,漏了一个都无法保证自身被干净的删除。

我们来分析一下,之所以这么麻烦,就是因为ActivePloy对Effect有一个引用。那么如果ActivePloy不引用Effect不就OK了?这个时候,让我们来试试弱引用。

  1. import weakref 
  2. class Effect(object):    
  3.     def __init__(self):    
  4.         self.active_ploy = ActivePloy(self)  
  5.   
  6.     def active(self):  
  7.         """激活时的处理"""  
  8.         pass  
  9.   
  10.   
  11. class ActivePloy(object):  
  12.     def __init__(self, effect):  
  13.         self.effect = weakref.proxy(effect) # 弱引用effect 
  14.   
  15.     def active(self):  
  16.         """激活时,激活对应效果"""  
  17.         self.effect.active() 

代码只有一个地方改变了,就是

  1. self.effect = weakref.proxy(effect) 

这句的效果就是self.effect可以像往常一样的使用,但是却不会增加effect的引用计数器。换言之,这样写,他们之间的交叉关系消失了!这个时候我们只需要单纯的删掉char.effect,Effect和ActivePloy的实例都会被销毁。

什么,假设ActivePloy在其他地方也被引用了?这样当然只有effect会被销毁。但是我们想让ActivePloy必然随着Effect的销毁而销毁,怎么办呢?那么我们可以改改,给弱引用加上一个回调函数:

  1. class ActivePloy(object):   
  2.     def __init__(self, effect):   
  3.         self.effect = weakref.proxy(effect, self.on_effect_destroy) # 弱引用effect  
  4.    
  5.     def active(self):   
  6.         """激活时,激活对应效果"""   
  7.         self.effect.active()  
  8.  
  9.     def on_effect_destroy(self, effect): 
  10.         """ 
  11.         effect销毁时会调用这个方法,在这里把对自己的引用都清理干净吧 
  12.         """ 
  13.         pass 

这样一来,就不用担心删不干净了。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯