个人其他博客地址:
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。 2:关于文章内容,有部分内容参考自互联网,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。
在java中,按以往的学习可以得知,我们的Java有四种引用包括,引用的存在主要是和垃圾回收机制所关联。
以上是在java机制存在的,但是在python没有存在上面几种,有只是有弱引用的说法。
什么是弱引用:在python里面可以理解为是原对象的地址一个代理。
弱引用存在的目的,其实也和我们的PVM的垃圾回收机制有关系。之前在说垃圾回收机制 XXXXXXXXXXXXXXXXXXXXX 中有介绍过,我们的pyton的回收垃圾机制是:
当对象的引用计数为0的时候,则进行回收。
所以python中弱引用的存在作用主要是:
1、在不增加对象的引用计数个数的情况下获得对象的引用(弱引用并不占用计数次数) 2、循环引用中减少循环引用,减少内存中不必要的对象存在的数量。 3、可以主动观察对象的引用计数,进行回收
引用计数变化示例:
使用弱引用前:
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
a = A1()
print(sys.getrefcount(a)) # 输出 2
b= a
print(sys.getrefcount(a))# 输出 3
使用弱引用后:
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
a = A1()
print(sys.getrefcount(a)) # 输出 2
b=weakref.ref(a)
print(sys.getrefcount(a)) # 输出 2
PS:weakref.ref(a) 弱引用对象也是一个对象,也需要分配地址 所以:
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
a = A1()
print(sys.getrefcount(a))
weakref_obj=weakref.ref(a)
print(sys.getrefcount(a))
print('a引用地址:',id(a))
print('弱引用对象的地址:',id(weakref_obj))
输出的结果为:
2
2
a引用地址:1943146576024
弱引用对象的地址:1943145890904
PS:weakref.ref(obj) 弱引用调用对象的属性或方法 对于的变量需加上()才变为对象
我们有了引用主要是为了调用相关的引用的对象的方法或属性。
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
a = A1()
print(sys.getrefcount(a))
weakref_obj=weakref.ref(a)
print(sys.getrefcount(a))
print('a引用地址:',id(a))
print('weakref.ref(a)弱引用对象的地址:',id(weakref.ref(a)))
print('weakref_obj弱引用变量的地址:',id(weakref_obj))
输出的结果为:
2
2
a引用地址:2387711670424
weakref.ref(a)弱引用对象的地址:2387710985304
weakref_obj弱引用变量的地址:2387710985304
上面的代码:PS:这里获取到是一个地址,如果是想获取弱引用变量所指的对象,需要加上()才是得到对象 上面的代码可以理解为:
weakref_obj=weakref.ref(a)=a引用地址
如果我使用弱引用的weakref_obj的变量去调用A1的相关的变量的,此时会报错滴!
print(weakref_obj.name)
因为weakref_obj它的对象是指是一个地址,不是一个对象。
需要转化为一个对象之后才可以去调用,方式是加上 弱引用对象(),加上一个():
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
a = A1()
print(sys.getrefcount(a))
weakref_obj=weakref.ref(a)
print(sys.getrefcount(a))
print('a引用地址:',id(a))
print('weakref.ref(a)弱引用对象的地址:',id(weakref.ref(a)))
print('weakref_obj弱引用变量的地址:',id(weakref_obj))
print(weakref_obj().name)
输出结果为:
2
2
a引用地址:2135388174488
weakref.ref(a)弱引用对象的地址:2135387489368
weakref_obj弱引用变量的地址:2135387489368
xiaozhong
PS:、weakref.proxy(obj)使用代理方式调用属性,不需要加()就可以充当是一个对象
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
a = A1()
print(sys.getrefcount(a))
weakref_obj_proxy = weakref.proxy(a) # 使用代理 引用计数不变
print(sys.getrefcount(a))
print('a引用地址:',id(a))
print(' weakref.proxy(a)弱引用对象的地址:',id( weakref.proxy(a)))
print('weakref_obj_proxy弱引用变量的地址:',id(weakref_obj_proxy))
print("查看最新的引用计数:",sys.getrefcount(a))
print('使用代理对象访问属性:',weakref_obj_proxy.name)
输出的结果为:
2
2
a引用地址:2162131944840
weakref.proxy(a)弱引用对象的地址:2162132075608
weakref_obj_proxy弱引用变量的地址:2162132075608
查看最新的引用计数:2
使用代理对象访问属性: xiaozhong
proxy和ref 构造函数接受一个可选的回调函数,删除所引用的对象是会调用这个函数。
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print(sys.getrefcount(a))
def callback_ref(self):
print("宁为玉碎,不为瓦全!")
weakref_obj_proxy = weakref.ref(a,callback_ref) # 使用ref 引用计数不变
del a
另一种匿名函数的写法:
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print(sys.getrefcount(a))
weakref_obj_proxy = weakref.ref(a,lambda ref: print("宁为玉碎,不为瓦全!", ref)) # 使用ref 引用计数不变
del a
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print(sys.getrefcount(a))
def callback_proxy(self):
print("宁为玉碎,不为瓦全!")
weakref_obj_proxy = weakref.proxy(a,callback_proxy) # 使用代理 引用计数不变
del a
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print('a当前引用计数',sys.getrefcount(a))
def callback_proxy(self):
print("宁为玉碎,不为瓦全!")
weakref_obj_proxy_001 = weakref.proxy(a,callback_proxy) # 使用代理 引用计数不变
weakref_obj_proxy_002 = weakref.proxy(a,callback_proxy) # 使用代理 引用计数不变
weakref_obj_proxy_003 = weakref.proxy(a,callback_proxy) # 使用代理 引用计数不变
print('weakref.proxy下==a对象被弱引用的次数',weakref.getweakrefcount(a)) # 1
print('weakref.proxy下==a被弱引用的对象列表',weakref.getweakrefs(a))
weakref_obj_ref_001 = weakref.ref(a,callback_proxy) # ref 引用计数不变
weakref_obj_ref_002 = weakref.ref(a,callback_proxy) # ref 引用计数不变
weakref_obj_ref_003 = weakref.ref(a,callback_proxy) # ref 引用计数不变
print('weakref.ref下==a对象被弱引用的次数',weakref.getweakrefcount(a)) # 1
print('weakref.ref下==a被弱引用的对象列表',weakref.getweakrefs(a))
输出的结果为:
a当前引用计数 2
weakref.proxy下==a对象被弱引用的次数 3
weakref.proxy下==a被弱引用的对象列表 [<weakproxy at 0x000001BE19CC0138 to A1 at 0x000001BE19A17710>, <weakproxy at 0x000001BE19CC00E8 to A1 at 0x000001BE19A17710>, <weakproxy at 0x000001BE19AF4458 to A1 at 0x000001BE19A17710>]
weakref.ref下==a对象被弱引用的次数 6
weakref.ref下==a被弱引用的对象列表 [<weakref at 0x000001BE19CD9098; to 'A1' at 0x000001BE19A17710>, <weakref at 0x000001BE19CD9048; to 'A1' at 0x000001BE19A17710>, <weakref at 0x000001BE19CC0958; to 'A1' at 0x000001BE19A17710>, <weakproxy at 0x000001BE19CC0138 to A1 at 0x000001BE19A17710>, <weakproxy at 0x000001BE19CC00E8 to A1 at 0x000001BE19A17710>, <weakproxy at 0x000001BE19AF4458 to A1 at 0x000001BE19A17710>]
我被回收了
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print('a当前引用计数',sys.getrefcount(a))
def callback_proxy(self):
print("宁为玉碎,不为瓦全!")
weakref_obj_proxy_001 = weakref.proxy(a) # 使用代理 引用计数不变
weakref_obj_proxy_002 = weakref.proxy(a) # 使用代理 引用计数不变
weakref_obj_proxy_003 = weakref.proxy(a) # 使用代理 引用计数不变
print('weakref.proxy下==a对象被弱引用的次数',weakref.getweakrefcount(a)) # 1
print('weakref.proxy下==a被弱引用的对象列表',weakref.getweakrefs(a))
weakref_obj_ref_001 = weakref.ref(a) # ref 引用计数不变
weakref_obj_ref_002 = weakref.ref(a) # ref 引用计数不变
weakref_obj_ref_003 = weakref.ref(a) # ref 引用计数不变
print('weakref.ref下==a对象被弱引用的次数',weakref.getweakrefcount(a)) # 1
print('weakref.ref下==a被弱引用的对象列表',weakref.getweakrefs(a))
输出的结果:
a当前引用计数 2
weakref.proxy下==a对象被弱引用的次数 1
weakref.proxy下==a被弱引用的对象列表 [<weakproxy at 0x000001A423844408 to A1 at 0x000001A423767710>]
weakref.ref下==a对象被弱引用的次数 2
weakref.ref下==a被弱引用的对象列表 [<weakref at 0x000001A423910098; to 'A1' at 0x000001A423767710>, <weakproxy at 0x000001A423844408 to A1 at 0x000001A423767710>]
我被回收了
:PS 有回调函数和没有回调函数的区别:
为什么需要引入字典的弱引用:
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print('a当前引用计数',sys.getrefcount(a))
# 创建一个普通字典
mydict = {}
# 作为字典的 key, a 指向的对象引用计数会加 1, 变成 2
mydict[a] = "我是A对象"
print('a当前引用计数',sys.getrefcount(a))
# 删除 a, 对对象无影响
del a
print(mydict)
输出的结果为:
a当前引用计数 2
a当前引用计数 3
{<__main__.A1 object at 0x000001BFD6AFBA20>: '我是A对象'}
我被回收了
使用字典增加了引用计数,使用弱引用字典则不会增加:
import sys
import weakref
class A1:
def __init__(self):
self.name = "xiaozhong"
self.age = 23
def __del__(self):
"""
:return: delete massage
"""
print("我被回收了")
a = A1()
print('a当前引用计数',sys.getrefcount(a))
# 创建一个弱引用字典
mydict = weakref.WeakKeyDictionary()
# 作为字典的 key, a 指向的对象引用计数会加 1, 变成 2
mydict[a] = "我是A对象"
print('a当前引用计数',sys.getrefcount(a))
del a
print(mydict)
输出的结果:
a当前引用计数 2
a当前引用计数 2
我被回收了
<WeakKeyDictionary at 0x1bdfd61f9b0>
意思就是:我不存在了,你也别想存在。用户在循环应用的示例:
PS:请原谅我的用中文来表示,纯属为了说明清楚:
import sys
class 皇帝:
def __del__(self):
print("皇帝驾崩了!")
def 下圣旨(self):
print("皇帝要说话了!!!!!!!!!!")
print("朕要今晚去XXX")
class 内监总管:
def __init__(self,分配一个皇帝):
self.内监总管服侍的皇帝 = 分配一个皇帝
# self.内监总管服侍的皇帝 = weakref.proxy(分配一个皇帝, self.on_destroy)
def on_destroy(self, effect):
"""
销毁时会调用这个方法
"""
pass
print('effect销毁时会调用这个方法')
def 说话(self):
print("圣旨到!!!")
try:
self.内监总管服侍的皇帝.下圣旨()
except:
print("你的皇帝已经没了!!!!没人会听你的圣旨")
def __del__(self):
print("总管大人你也随着皇帝一起吧!")
# 建立一个皇帝对象
康熙皇帝 = 皇帝()
print("康熙皇帝的引用计数:",sys.getrefcount(康熙皇帝))
# 建立一个太监总管
不知道名称内监总管 = 内监总管(康熙皇帝)
不知道名称内监总管.说话()
print("康熙皇帝的引用计数:",sys.getrefcount(康熙皇帝))
del 康熙皇帝
print("=======================")
print("康熙皇帝驾崩了!!!!")
不知道名称内监总管.说话()
print("=======================")
输出的结果:
康熙皇帝的引用计数:2
圣旨到!!!
皇帝要说话了!!!!!!!!!!
朕要今晚去XXX
康熙皇帝的引用计数:3
=======================
康熙皇帝驾崩了!!!!
圣旨到!!!
皇帝要说话了!!!!!!!!!!
朕要今晚去XXX
=======================
总管大人你也随着皇帝一起吧!
皇帝驾崩了!
上面最诡异的地方是:
del 康熙皇帝 康熙皇帝驾崩了!!!!
圣旨到!!!
皇帝要说话了!!!!!!!!!!
朕要今晚去XXX
使用弱引用的话:
#!/usr/bin/evn python
# coding=utf-8
import weakref
import sys
class 皇帝:
def __del__(self):
print("皇帝驾崩了!")
def 下圣旨(self):
print("皇帝要说话了!!!!!!!!!!")
print("朕要今晚去XXX")
class 内监总管:
def __init__(self,分配一个皇帝):
# self.内监总管服侍的皇帝 = 分配一个皇帝
self.内监总管服侍的皇帝 = weakref.proxy(分配一个皇帝, self.on_destroy)
def on_destroy(self, effect):
"""
销毁时会调用这个方法
"""
pass
print('effect销毁时会调用这个方法')
def 说话(self):
print("圣旨到!!!")
try:
self.内监总管服侍的皇帝.下圣旨()
except:
print("你的皇帝已经没了!!!!没人会听你的圣旨")
def __del__(self):
print("总管大人你也随着皇帝一起吧!")
# 建立一个皇帝对象
康熙皇帝 = 皇帝()
print("康熙皇帝的引用计数:",sys.getrefcount(康熙皇帝))
# 建立一个太监总管
不知道名称内监总管 = 内监总管(康熙皇帝)
不知道名称内监总管.说话()
print("康熙皇帝的引用计数:",sys.getrefcount(康熙皇帝))
del 康熙皇帝
print("=======================")
print("康熙皇帝驾崩了!!!!")
不知道名称内监总管.说话()
print("=======================")
输出结果:
康熙皇帝的引用计数:2
圣旨到!!!
皇帝要说话了!!!!!!!!!!
朕要今晚去XXX
康熙皇帝的引用计数:2
皇帝驾崩了!
effect销毁时会调用这个方法
=======================
康熙皇帝驾崩了!!!!
圣旨到!!!
你的皇帝已经没了!!!!没人会听你的圣旨
=======================
总管大人你也随着皇帝一起吧!
注意点:
圣旨到!!!
你的皇帝已经没了!!!!没人会听你的圣旨
这个就正常了!!!
以上是个人对弱引用的总结
https://blog.csdn.net/z_feng12489/article/details/89433878
原文作者:程序员小钟同学;如有侵权,请联系管理员删除。