potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

Python 3.4 RubyのDir.chdir(path) {...}様の処理

はじめに

Python 3.4(3?)の__enter____exit__を使うとRubyのDir.chdir(path) {...}の様にブロックを抜けたらカレントディレクトリを元に戻す様な処理も簡単に書けます。また、contextlib.contextmanagerデコレーター(3.4リファレンス)を使うこともできます。短いコードであれば後者の方が読みやすく書けるかと思います。

覚書までに。

12月4日:podhmoさんからアドバイスを頂いたので追記しました。

__enter__/__exit__を使う方法

chdir.py

#coding: utf-8
import os

#with構文で使用して一時的に作業ディレクトリを変更するためのクラス
class ChDir(object):
    def __init__(self, path):
        self.__prev_path = os.getcwd()
        os.chdir(path)

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        os.chdir(self.__prev_path)
        return False

#サンプルコード
if __name__ == "__main__":
    with ChDir(os.pardir):
        print(os.listdir(os.curdir)) #カレントディレクトリの親ディレクトリのファイル一覧が表示される。
    print("-----")
    print(os.listdir(os.curdir)) #カレントディレクトリのファイル一覧が表示される。

コンテキストマネージャ(コンテキストマネージャのファクトリ関数)を使う方法

chdir.py

#coding: utf-8
import os
from contextlib import contextmanager

#with構文で使用して一時的に作業ディレクトリを変更するためのコンテキストマネージャのファクトリ関数
@contextmanager
def ChDir(path):
        prev_path = os.getcwd()
        os.chdir(path)
        yield
        os.chdir(prev_path)

#サンプルコード
if __name__ == "__main__":
    with ChDir(os.pardir):
        print(os.listdir(os.curdir)) #カレントディレクトリの親ディレクトリのファイル一覧が表示される。
    print("-----")
    print(os.listdir(os.curdir)) #カレントディレクトリのファイル一覧が表示される。

備考

contextlibはContextDecoratorというクラス(3.4リファレンス)を提供しています。このクラスを継承することで関数デコレーターでありコンテクストマネージャーであるクラスを作成することもできます。