34

オブジェクトの存続期間中存続し、その後削除されるフォルダーの一時ワークスペースを生成するクラスを作成しています。def initで tempfile.mkdtemp() を使用してスペースを作成していますが、 delが呼び出されることに依存できないことを読みました。

私はこのようなものが欲しいです:

class MyClass:
  def __init__(self):
    self.tempfolder = tempfile.mkdtemp()

  def ... #other stuff

  def __del__(self):
    if os.path.exists(self.tempfolder): shutil.rmtree(self.tempfolder)

このクリーンアップを処理する別の/より良い方法はありますか? 「with」について読んでいましたが、関数内でのみ役立つようです。

4

5 に答える 5

51

警告:一時フォルダーが削除されることを保証することはできません。これは、ユーザーが常にプロセスを強制終了し、他のプロセスを実行できなくなる可能性があるためです。

そうは言っても、そうする

temp_dir = tempfile.mkdtemp()
try:
    <some code>
finally:
    shutil.rmtree(temp_dir)

これは非常に一般的な操作であるため、Python には「何かを行い、コードを実行し、クリーンアップする」ことをカプセル化する特別な方法があります:コンテキスト マネージャーです。次のように独自に記述できます。

@contextlib.contextmanager
def make_temp_directory():
    temp_dir = tempfile.mkdtemp()
    try:
        yield temp_dir
    finally:
        shutil.rmtree(temp_dir)

そしてそれを次のように使用します

with make_temp_directory() as temp_dir:
    <some code>

(これは@contextlib.contextmanagerショートカットを使用してコンテキスト マネージャーを作成することに注意してください。元の方法で実装する場合は、__enter__および__exit__メソッドを使用してカスタム クラスを作成する必要があります。__enter__は一時ディレクトリを作成して返し、それを__exit__削除します。

于 2012-11-14T13:42:59.657 に答える
24

一時ファイルとディレクトリを処理する良い方法は、コンテキスト マネージャーを使用することです。これは、 tempfile.TemporaryFileまたはtempfile.NamedTemporaryFileを使用する方法です。 with(通常の終了、リターン、例外、またはその他の方法で) ステートメントを終了すると、ファイル/ディレクトリとその内容がファイル システムから削除されます。

Python 3.2+ の場合、これはtempfile.TemporaryDirectoryとして組み込まれています。

import tempfile

with tempfile.TemporaryDirectory() as temp_dir:
    ... do stuff ...

以前のバージョンの Python では、独自のコンテキスト マネージャーを簡単に作成して、まったく同じことを行うことができます。ここでの@katrielalexの回答との違いはmkdtemp()、例外が発生した場合にディレクトリが確実にクリーンアップされるようにするための引数の受け渡しとtry/finallyブロックです。

import contextlib
import shutil

@contextlib.contextmanager
def temporary_directory(*args, **kwargs):
    d = tempfile.mkdtemp(*args, **kwargs)
    try:
        yield d
    finally:
        shutil.rmtree(d)


# use it
with temporary_directory() as temp_dir:
    ... do stuff ...

プロセスが強制終了された場合 (例: kill -9)、ディレクトリはクリーンアップされないことに注意してください。

于 2014-02-21T00:07:04.060 に答える
4

もう 1 つの使用方法contextlibは、オブジェクトを閉じられるようにして、closingコンテキスト マネージャーを使用することです。

class MyClass:
    def __init__(self):
        self.tempfolder = tempfile.mkdtemp()

    def do_stuff():
        pass

    def close(self):
        if os.path.exists(self.tempfolder):
            shutil.rmtree(self.tempfolder)

次に、コンテキストマネージャーを使用します。

from contextlib import closing

with closing(MyClass()) as my_object:
    my_object.do_stuff()
于 2014-10-24T07:13:05.363 に答える
2

Bluewindで述べられているように、コンテキスト マネージャーの yield 部分を try: finally ステートメント内にラップする必要があります。そうしないと、コンテキスト マネージャー内で例外が正しく処理されません。

Python 2.7 ドキュメントから

ジェネレーターが生成された時点で、 with ステートメントでネストされたブロックが実行されます。ブロックが終了すると、ジェネレーターが再開されます。ブロック内で未処理の例外が発生した場合、生成器内で生成された時点で例外が再発生します。したがって、try...except...finally ステートメントを使用してエラー (存在する場合) をトラップしたり、何らかのクリーンアップを確実に実行したりすることができます。(完全に抑制するのではなく) 例外をログに記録するため、または何らかのアクションを実行するためだけに例外がトラップされた場合、ジェネレーターはその例外を再発生させる必要があります。それ以外の場合、ジェネレーターのコンテキスト マネージャーは with ステートメントに例外が処理されたことを示し、with ステートメントの直後のステートメントから実行が再開されます。

また、Python 3.2+ を使用している場合は、上記のすべてがうまくまとめられたこの小さな gemをチェックしてください。

tempfile.TemporaryDirectory(サフィックス=''、プレフィックス='tmp'、ディレクトリ=なし)

この関数は、mkdtemp() を使用して一時ディレクトリを作成します (提供された引数は、基になる関数に直接渡されます)。結果のオブジェクトは、コンテキスト マネージャーとして使用できます (With Statement Context Managers を参照)。コンテキストが完了すると (または一時ディレクトリ オブジェクトが破棄されると)、新しく作成された一時ディレクトリとそのすべての内容がファイル システムから削除されます。

ディレクトリ名は、返されたオブジェクトの name 属性から取得できます。

ディレクトリは cleanup() メソッドを呼び出すことで明示的にクリーンアップできます。

バージョン 3.2 の新機能。

于 2013-10-29T11:30:11.027 に答える