web-dev-qa-db-ja.com

urllib.urlopen()の後にclose()を呼び出す必要がありますか?

私はPythonが初めてで、他の誰かのコードを読んでいます:

urllib.urlopen()の後にurllib.close()が続くべきですか?そうしないと、接続がリークしますよね?

69
Nikita

closeメソッドは、urllib.urlopenresulturllibモジュール自体のnotで呼び出す必要がありますあなたが考えているように(あなたがurllib.closeに言及したように-これは存在しません)。

最善のアプローチ:x = urllib.urlopen(u)などの代わりに、以下を使用します。

import contextlib

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

withステートメントおよびclosingコンテキストマネージャーは、例外が存在する場合でも適切に閉じられるようにします。

100
Alex Martelli

@Peterが言うように、スコープ外で開かれたURLはガベージコレクションの対象になります。

ただし、urllib.py定義:

 def __del__(self):
        self.close()

これは、そのインスタンスの参照カウントがゼロに達すると、その __del__ メソッドが呼び出されるため、そのcloseメソッドも呼び出されます。参照カウントがゼロに達するための最も「通常の」方法は、単にインスタンスをスコープから外すことですが、明示的なdel x早期(ただし、直接呼び出しません__del__ただし、参照カウントを1だけ減らします。

リソースを明示的に閉じることは確かに良いスタイルです-特にアプリケーションが上記のリソースを使いすぎるリスクを実行する場合-しかしPythonwill不要なインスタンスへの(循環?)参照を維持するなど、おかしなことをしない場合は、自動的にクリーンアップします。

12
Mark Rushakoff

厳密に言えば、これは事実です。しかし、実際には、urllibがスコープから外れると、自動ガベージコレクターによって接続が閉じられます。

4
Peter

基本的にdoIronPythonを使用する場合は、明示的に接続を閉じる必要があります。スコープ外への自動クローズは、ガベージコレクションに依存しています。ガベージコレクションが長時間実行されず、Windowsがソケットを使い果たしてしまうという状況に陥りました。私は高頻度でWebサーバーをポーリングしていました(つまり、IronPythonと接続で可能な限りの高さ、約7Hz)。 PerfMonで「確立された接続」(つまり、使用中のソケット)が上下することがわかりました。解決策は、urlopenを呼び出すたびにgc.collect()を呼び出すことでした。

0
Jann Poppinga