1. ホーム
  2. python

[解決済み] Pythonのオブジェクトを正しくクリーンアップするにはどうしたらいいですか?

2022-03-19 15:04:03

質問

class Package:
    def __init__(self):
        self.files = []

    # ...

    def __del__(self):
        for file in self.files:
            os.unlink(file)

__del__(self) 上記はAttributeError例外で失敗します。 私は理解しています Pythonは が存在する場合、グローバル変数(この文脈ではメンバデータ? __del__() が呼び出されます。 もしそうなら、そしてこれが例外の理由なら、どうすればオブジェクトが適切に破壊されることを確認できるでしょうか?

解決方法は?

Pythonの with 文は、クリーンアップが必要なリソースを管理するために使用します。 明示的な close() ステートメントを呼び出すことを忘れてしまったり、それを finally ブロックを作成し、例外発生時のリソースリークを防いでいます。

を使用するには with 文の中で、以下のメソッドを持つクラスを作成します。

  def __enter__(self)
  def __exit__(self, exc_type, exc_value, traceback)

上記の例では

class Package:
    def __init__(self):
        self.files = []

    def __enter__(self):
        return self

    # ...

    def __exit__(self, exc_type, exc_value, traceback):
        for file in self.files:
            os.unlink(file)

そして、誰かがあなたのクラスを使いたいと思ったとき、次のようにします。

with Package() as package_obj:
    # use package_obj

変数 package_obj は Package 型のインスタンスになります (これは __enter__ メソッド)。 その __exit__ メソッドは、例外の発生有無にかかわらず、自動的に呼び出されます。

このアプローチをさらに一歩進めることもできます。 上記の例では,誰かがパッケージのインスタンスを作成する際に with 節があります。 そんなことは起こって欲しくないですよね。 PackageResourceクラスを作成し、そのクラスで __enter____exit__ メソッドを使用します。 そうすると、Packageクラスは厳密には __enter__ メソッドで返されます。 そうすれば呼び出し側は with ステートメントを使用します。

class PackageResource:
    def __enter__(self):
        class Package:
            ...
        self.package_obj = Package()
        return self.package_obj

    def __exit__(self, exc_type, exc_value, traceback):
        self.package_obj.cleanup()

これを次のように使うのです。

with PackageResource() as package_obj:
    # use package_obj