前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python的弱引用

Python的弱引用

作者头像
py3study
发布2020-01-06 14:38:05
9030
发布2020-01-06 14:38:05
举报
文章被收录于专栏:python3python3

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

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

代码语言:javascript
复制
char.effect = Effect() # 给角色添加一个效果

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

代码语言:javascript
复制
class Effect(object):       def __init__(self):           self.active_ploy = ActivePloy(self)      def active(self):         """激活时的处理"""         pass   class ActivePloy(object):     def __init__(self, effect):         self.effect = effect      def active(self):         """激活时,激活对应效果"""         self.effect.active() 

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

代码语言:javascript
复制
del char.effect 

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

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

代码语言:javascript
复制
class Effect(object):        def __init__(self):            self.active_ploy = ActivePloy(self)        def active(self):          """激活时的处理"""          pass        def destroy(self):         self.active_ploy.destroy()   class ActivePloy(object):      def __init__(self, effect):          self.effect = effect        def active(self):          """激活时,激活对应效果"""          self.effect.active()      def destroy(self):         self.effect = None 

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

代码语言:javascript
复制
char.effect.destroy() del char.effect 

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

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

代码语言:javascript
复制
import weakref class Effect(object):        def __init__(self):            self.active_ploy = ActivePloy(self)        def active(self):          """激活时的处理"""          pass      class ActivePloy(object):      def __init__(self, effect):          self.effect = weakref.proxy(effect) # 弱引用effect       def active(self):          """激活时,激活对应效果"""          self.effect.active() 

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

代码语言:javascript
复制
self.effect = weakref.proxy(effect) 

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

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

代码语言:javascript
复制
class ActivePloy(object):       def __init__(self, effect):           self.effect = weakref.proxy(effect, self.on_effect_destroy) # 弱引用effect         def active(self):           """激活时,激活对应效果"""           self.effect.active()       def on_effect_destroy(self, effect):         """         effect销毁时会调用这个方法,在这里把对自己的引用都清理干净吧         """         pass 

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档