为何deepcopy weakref.proxy会复制目标对象?谁持有引用?与weakref.ref差异是否为预期?
关于weakref.proxy与weakref.ref的deepcopy行为差异解析
1. 行为差异的本质原因
你没有误解测试结果,这种差异是有意设计的,源于两者的定位完全不同:
weakref.proxy是透明代理对象:它的核心设计目标是让使用者能像操作原对象一样操作代理。当执行deepcopy时,copy模块会自动穿透代理,直接对原对象执行深拷贝,最终返回的是原对象的拷贝实例(而非代理的拷贝)。weakref.ref是弱引用容器:它本身是一个独立的可调用对象,仅用于存储原对象的弱引用。对它执行deepcopy时,复制的只是这个容器本身,而非它指向的目标对象,因此拷贝后的引用仍然指向原对象。
2. 拷贝出的A实例未被GC的原因
proxy_deepcopy变量本身就是拷贝后的A实例(不是代理),它持有该实例的强引用。只要这个变量存在于当前作用域中,Python的垃圾回收机制就不会回收该实例。
3. 验证代码与结果解析
weakref.proxy的深拷贝行为
import copy import weakref class A: def __init__(self, val=3): self.val = val def identify(self): return id(self) a = A() proxy = weakref.proxy(a) proxy.val = 4 proxy_deepcopy = copy.deepcopy(proxy) proxy_deepcopy.val = 5 print(a.val, a.identify()) # 4 139732708115984 print(proxy.val, proxy.identify()) # 4 139732708115984 print(proxy_deepcopy.val, proxy_deepcopy.identify()) # 5 139732690146640
这里proxy_deepcopy是原对象a的独立深拷贝实例,和a拥有不同的内存地址,修改它的属性不会影响原对象。
weakref.ref的深拷贝行为
import copy import weakref class A: def __init__(self, val=3): self.val = val def identify(self): return id(self) a = A() proxy = weakref.ref(a) proxy().val = 4 proxy_deepcopy = copy.deepcopy(proxy) proxy_deepcopy().val = 5 print(a.val, a.identify()) # 5 140323837493200 print(proxy().val, proxy().identify()) # 5 140323837493200 print(proxy_deepcopy().val, proxy_deepcopy().identify()) # 5 140323837493200
这里proxy_deepcopy是原weakref.ref容器的拷贝,它指向的仍然是原对象a,因此通过它修改属性会直接作用在a上。
总结
weakref.proxy的深拷贝会穿透代理复制原对象,返回原对象的拷贝实例;weakref.ref的深拷贝仅复制引用容器,始终指向原对象。- 这种差异是有意设计的,完全符合两者的定位:一个是模拟原对象的透明代理,一个是管理弱引用的独立容器。
- 拷贝后的A实例被
proxy_deepcopy变量持有强引用,因此不会被立即回收。
内容的提问来源于stack exchange,提问作者mutableVoid
相关产品推荐
相关产品推荐

