我应该在urllib.urlopen()之后调用close()吗?


71

我是Python的新手,正在阅读别人的代码:

应该urllib.urlopen()跟着urllib.close()?否则,会泄漏连接,对吗?

Answers:


104

close方法必须在的结果上调用urllib.urlopen而不是urllib您正在考虑的模块本身上调用(如您所提到的urllib.close-不存在)。

最好的方法:代替x = urllib.urlopen(u)etc,使用:

import contextlib

with contextlib.closing(urllib.urlopen(u)) as x:
   ...use x at will here...

with语句和closing上下文管理器将确保即使在出现异常的情况下也能正确关闭。


11
怎么做类似的事情data = urllib2.urlopen('url').read()
Facundo Casco '10

15
在Python 3中,添加了对with语句的直接支持。用了urllib.urlopen(U)为x:...
埃里克·阿劳霍

为什么在python3文档仍然提到contextlib.closing这个(啊哈)范围内?
user66081

@ÉricAraujo:在python 3中,urllib.urlopen根本不存在。
埃里克(Eric)

:它被转移到一个新的子模块urllib.request里docs.python.org/3/library/...
埃里克·阿劳霍

12

就像@Peter所说的那样,超出范围的URL将有资格进行垃圾回收。

但是,还要注意urllib.py定义:

 def __del__(self):
        self.close()

这意味着当该实例的引用计数达到零时,其__del__方法将被调用,因此其close方法也将被调用。引用计数达到零的最“正常”方式是简单地使实例超出范围,但没有严格阻止您从明确的del x早期开始的方法(但是,它不会直接调用,__del__而只是将引用计数减一)。

显式关闭资源当然是个好方法-尤其是当您的应用程序冒着使用过多上述资源的风险时-但是,如果您不做任何维护(循环引用)之类的事情,Python自动为您清理到您不再需要的实例。


2
但是,有可能使垃圾收集器超负荷运行-在某些情况下,我创建文件句柄的速度比关闭它们的速度要快[但是显式gc.collect()调用或a会close()清理掉它们]。
查尔斯·达菲

4

严格来说,这是真的。但是实际上,一旦urllib超出范围,连接将被自动垃圾收集器关闭。


11
对于某些Python实现,这是正确的,但是Python语言不能保证一旦对象超出范围,就将立即关闭。cf. jython
John La Rooy

1
@gnibbler这个答案的作者没有说它会马上发生。
Piotr Dobrogost'4

3
@Piotr,但是如果我有一个循环打开网址并且GC无法足够快地获取网址,则程序可能会崩溃。这是一种很草率的处理方式,不属于生产代码。
约翰·拉鲁伊

1
无操作GC(即永远不会运行的GC)对于Python完全有效。您不能保证GC会运行。并且gc.disable可以在大多数Python实现中禁用GC。
gsnedders

1
在GC进行任何清理之前,我设法用尽了可用的连接。因此,是的,如果您不想突然发现连接中断,就应该打电话给close。
安德鲁·帕特

1

使用IronPython时,基本上确实需要显式关闭连接。超出范围时自动关闭取决于垃圾回收。我遇到了这样一种情况,即垃圾收集没有运行很长时间,以至于Windows用尽了套接字。我正在以较高的频率轮询Web服务器(即,与IronPython一样高,并且连接允许的频率约为7Hz)。我可以看到“已建立的连接”(即正在使用的套接字)在PerfMon上不断上升。解决的方法是在每次致电后都致电。gc.collect()urlopen


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.