如何嵌套任意数量的Python文件上下文管理器?

如何嵌套任意数量的Python文件上下文管理器?,python,python-2.7,contextmanager,Python,Python 2.7,Contextmanager,我希望采用任意数量的路径来表示嵌套的tar归档文件,并在最里面的归档文件上执行操作。问题是,嵌套可以是任意的,因此我需要的上下文管理器的数量也是任意的 例如: ARCHIVE_PATH = "path/to/archive.tar" INNER_PATHS = ( "nested/within/archive/one.tar", "nested/within/archive/two.tar", # Arbitary number of these ) def list

我希望采用任意数量的路径来表示嵌套的tar归档文件,并在最里面的归档文件上执行操作。问题是,嵌套可以是任意的,因此我需要的上下文管理器的数量也是任意的

例如:

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))
我不能将
语句一起使用,因为可以嵌套任意数量的级别。我不能使用,因为文件上说:

…使用
nested()
打开两个文件是编程错误,因为如果在打开第二个文件时引发异常,第一个文件将不会立即关闭


有没有一种方法可以使用语言构造来实现这一点,或者我需要手动管理自己的打开文件对象堆栈?

在这种情况下,您可以使用递归。这种情况感觉最自然(当然,如果Python中还没有特殊处理):


这似乎是唯一简单的解决办法。可以编写一个自定义上下文管理器,手动调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,但是,要处理异常以使其按预期的方式运行就变得非常困难了。在3.3中!我不知道这是在python3.3中添加的。看起来是一个非常干净的解决方案。@delnan,很好的提示!否则,请查看我以前的问题:
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