Python self=None做什么?
我在看书。请注意,在方法的末尾有一个Python self=None做什么?,python,garbage-collection,python-internals,python-asyncio,Python,Garbage Collection,Python Internals,Python Asyncio,我在看书。请注意,在方法的末尾有一个self=None语句。它有什么作用 def _run(self): try: self._callback(*self._args) except Exception as exc: msg = 'Exception in callback {}{!r}'.format(self._callback, sel
self=None
语句。它有什么作用
def _run(self):
try:
self._callback(*self._args)
except Exception as exc:
msg = 'Exception in callback {}{!r}'.format(self._callback,
self._args)
self._loop.call_exception_handler({
'message': msg,
'exception': exc,
'handle': self,
})
self = None # Needed to break cycles when an exception occurs.
我原以为它会删除该实例,但下面的测试不建议这样做:
class K:
def haha(self):
self = None
a = K()
a.haha()
print(a) # a is still an instance
它只是清除对
self
的本地引用,确保如果发生异常,传递给self的引用。\u loop.call\u exception\u handler()
是唯一剩余的引用,并且没有创建循环
这里仍然需要这样做,因为异常回溯引用了本地名称空间;当函数退出时,不会被清除,因为引用的局部变量仍然存在
这记录在中,并带有警告:
警告:将回溯返回值指定给处理异常的函数中的局部变量将导致循环引用。这将防止同一函数中的局部变量或回溯引用的任何内容被垃圾收集。由于大多数函数不需要访问回溯,因此最好的解决方案是使用类似于exctype,value=sys.exc_info()[:2]
的方法来仅提取异常类型和值。如果确实需要回溯,请确保在使用后将其删除(最好使用try…finally
语句),或者在本身不处理异常的函数中调用exc_info()
因为tulip
处理程序构成了一个基本的框架类,所以代码通过从本地名称空间中删除self
来处理回溯循环引用情况,因为它不能保证\u callback
或call\u exception\u handler
函数将清除它们的引用
在CPython中,当对象的引用计数下降到0时,对象将被销毁,但循环引用(一系列对象在一个循环中引用自己)永远不会看到其引用计数下降到0。垃圾收集器确实试图打破这种循环,但它不能总是这样做或速度不够快。显式清除引用可避免创建循环
例如,如果存在\uuu del\uu
方法,垃圾收集器将不会中断循环,因为它不知道在这种情况下安全中断循环的顺序
即使没有
\uuuu del\uuuu
方法(框架类永远不应该假设这种情况不会发生),最好不要依赖垃圾收集器最终清除周期。注意,这一行是由Guido引入的
在此版本中,与\u run
相对应的功能是:
tulip\u log
只是一个普通的记录器:logging.getLogger(“tulip”)
在引擎盖下,Logger.exception
将sys.exc_info()
的结果存储在LogRecord
中,但在调用exception
后,记录对象不会持久存在
为了验证logging.exception
不会导致引用循环,我做了以下实验:
import time
import logging
class T:
def __del__(self):
print('T.__del__ called')
def test(self):
try:
1 / 0
except Exception:
logging.exception("Testing")
def run():
t = T()
t.test()
# t is supposed to be garbaged collected
run()
time.sleep(10) # to emulate a long running process
结果是:
$ python test.py
ERROR:root:Testing
Traceback (most recent call last):
File "test.py", line 11, in test
1 / 0
ZeroDivisionError: integer division or modulo by zero
T.__del__ called
对象t
按预期进行垃圾收集
因此,我认为这里不需要分配
self=None
。也许问题应该是“为什么可以将self
设置为None
中断周期?什么周期?”你能举一个这样的循环引用的例子吗?我仍然不明白。。。我的意思是,如果语句self=None
被命中,那么很明显,方法的结尾将被命中,在这种情况下,本地引用将退出范围,那么为什么我们需要self=None
?@msvalkon:任何直接或间接引用对象的操作都可以self.ref=self
是最简单的例子。@MartijnPieters我不明白,是不是还有一个圆圈,也就是说,self
->\u loop
->self
,在我们从locals()
中删除对self
的引用之后的事件,但至少,self->call\u exception\u handler->exc->\u traceback\u\u->f\u locals->self
循环消失了。相同的提交在多个位置添加了self=None
,因为框架这样做是很好的实践,并不是因为代码库单独显示循环引用。@MartijnPieters您能给我举一个生成循环引用的例子吗?可能是通过\u回调?我还没有研究过tulip/asyncio库;我不知道设计意图,也不知道您所研究的提交是否是一项正在进行的工作(例如,即使在当时还没有完整的库)。而日志记录
库允许您注册自定义处理程序和格式化程序;不要只使用默认的代码库。不幸的是,我现在没有时间构建一个示例案例ATM(此评论来自3G连接上的智能手机)。
$ python test.py
ERROR:root:Testing
Traceback (most recent call last):
File "test.py", line 11, in test
1 / 0
ZeroDivisionError: integer division or modulo by zero
T.__del__ called