2013-04-28 11 views
5

ネストしたtarアーカイブを表す任意の数のパスを取得し、最も内側のアーカイブに対して操作を実行したいとします。問題は、ネストは任意である可能性があるため、必要なコンテキストマネージャの数も任意です。任意の数のPythonファイルコンテキストマネージャをネストできますか?

には、例えば、テイク:巣に任意の数のレベルがある可能性があるため

ARCHIVE_PATH = "path/to/archive.tar" 

INNER_PATHS = (
    "nested/within/archive/one.tar", 
    "nested/within/archive/two.tar", 
    # Arbitary number of these 
) 

def list_inner_contents(archive_path, inner_paths): 
    with TarFile(archive_path) as tf1: 
     with TarFile(fileobj=tf1.extractfile(inner_paths[0])) as tf2: 
      with TarFile(fileobj=tf2.extractfile(inner_paths[1])) as tf3: 
       # ...arbitary level of these! 
       return tfX.getnames() 

contents = list_inner_contents(ARCHIVE_PATH, INNER_PATHS)) 

私はwith文のnesting syntaxを使用することはできません。ドキュメントがすぐそこに言うので、私はcontextlib.nestedを使用することはできません。

...例外がスローされた場合には、第2を開いたときに最初のファイルを迅速にクローズされませんように2つのファイルを開くにはnested()を使用すると、プログラミングエラーですファイル。

これを行うには言語構造を使用する方法がありますか、または開いているファイルオブジェクトの独自のスタックを手動で管理する必要がありますか?

+2

は3.3で、あなたは[ 'contextlib.ExitStack'](HTTPを使用することができます。 org/3/library/contextlib.html#contextlib.ExitStack)。 – delnan

+0

@delnan - 私はPython 3を使わないように**依存しています:/ – detly

+0

@delnan Nice!私はこれがpython3.3で追加されたことを知らなかった。本当にきれいな解決策と思われます。 – Bakuriu

答えて

4

この場合、再帰を使用することができます。それは(Pythonで特別な治療法はまだありません場合はもちろんの)場合のために最も自然であることを感じている://docs.python:

ARCHIVE_PATH = "path/to/archive.tar" 

INNER_PATHS = [ 
    "nested/within/archive/one.tar", 
    "nested/within/archive/two.tar", 
    # Arbitary number of these 
] 

def list_inner_contents(archive_path, inner_paths): 
    def rec(tf, rest_paths): 
     if not rest_paths: 
      return tf.getnames() 

     with TarFile(fileobj=tf.extractfile(rest_paths[0])) as tf2: 
      return rec(tf2, rest_paths[1:]) 

    with TarFile(archive_path) as tf: 
     try: 
      return rec(tf, inner_paths) 
     except RuntimeError: 
      # We come here in case the inner_paths list is too long 
      # and we go too deeply in the recursion 
      return None 
+1

これは唯一の簡単な解決策です。 '__enter__'と' __exit__'メソッドを手動で呼び出すカスタムコンテキストマネージャーを書くことができますが、それが予想どおりに動作するように例外を処理することは本当に難しくなります。 – Bakuriu

関連する問題