Python调用sys.getrefcount()时析构函数意外触发的原因咨询
问题分析与解答
首先明确两次触发__del__的具体原因:
第一次触发__del__(执行b = f()时)
执行b = a()后,变量b指向a类的实例,此时实例的引用计数为1。当执行b = f(),b被重新赋值为字符串'something',原来的a实例失去所有引用,引用计数降为0,Python垃圾回收机制自动调用该实例的__del__方法,输出getting rid of something,这是正常的对象销毁逻辑。
第二次触发__del__(调用sys.getrefcount(b)时)
你提到调用sys.getrefcount(b)时触发__del__并返回3,核心原因是交互环境的额外引用与函数调用的临时引用共同作用:
- 交互环境的内置变量引用:Python交互shell会将最后一次执行的表达式结果赋值给内置变量
_。如果调用sys.getrefcount(b)前,你曾直接输入b查看实例,_会额外引用该实例,此时实例引用计数变为2(b+_)。 sys.getrefcount的临时引用:调用该函数时,参数传递会临时增加实例的引用计数1,此时总引用计数为3(b+_+ 函数参数),因此getrefcount返回3。- 引用计数回落触发销毁:函数执行完毕后,临时的参数引用被释放;当你输入新命令时,内置变量
_会被新结果覆盖,原来的实例引用计数降为0,从而触发__del__方法。
另外,你的__del__方法中del self是多余的——__del__本身就是对象销毁前的回调,此时self是对象的最后一个局部引用,del self不会改变对象的销毁逻辑,反而容易造成误解。
验证示例
在交互shell中执行以下步骤可复现该现象:
>>> import sys >>> class a: ... def __del__(self): ... print('getting rid of something') ... >>> b = a() >>> b # 此时_会引用该实例,引用计数变为2 <__main__.a object at 0x10xxxxxx> >>> sys.getrefcount(b) # 总引用计数为3,返回3 3 >>> 1+1 # 输入新命令,_被新结果覆盖 2 getting rid of something # 实例引用计数降为0,触发__del__
内容的提问来源于stack exchange,提问作者KARAN CHOUDHARY
相关产品推荐
相关产品推荐

