使用TarFile.extractfile()作为上下文管理器触发AttributeError: __enter__
问题分析
AttributeError: __enter__ 错误的核心原因是:tarfile.extractfile() 返回的 ExtractFile 对象未实现上下文管理器所需的 __enter__ 和 __exit__ 方法,导致无法直接用 with 语句进行资源管理。这种情况常见于 Python 3.2 之前的版本,或是部分特殊场景下的 tar 文件对象。
解决方法
方法1:用contextlib.closing包装返回对象
contextlib.closing 可以为任何带有 close() 方法的对象补全上下文管理器接口,完美适配 ExtractFile:
from contextlib import closing # 修改readfile函数 if tarfile.is_tarfile(data): tardata = tarfile.open(data, "r") files = tardata.getmembers() def readfile(data_pt): # 先过滤目录,避免extractfile返回None if not data_pt.isfile(): return None return closing(tardata.extractfile(data_pt))
修改后你的原循环代码可正常运行,closing 会在 with 块结束时自动调用文件的 close() 方法。
方法2:手动管理文件的打开与关闭
如果不想引入额外模块,直接用 try/finally 手动管控资源:
for file in files: # 跳过目录,避免处理空对象 if not file.isfile(): continue openfile = readfile(file) try: molecules.append(process_file_fn(openfile)) finally: openfile.close()
方法3:升级Python版本
从 Python 3.2 开始,tarfile.ExtractFile 已原生支持上下文管理器接口。若你使用的是较老版本,升级到 3.2+ 后无需修改代码即可直接使用原逻辑。
额外注意点
tardata.getmembers()会返回 tar 包中的目录对象,调用extractfile()处理目录会返回None,同样会触发with语句报错,必须用data_pt.isfile()做判断过滤。- 你的
.tar.bz2格式文件无需额外指定压缩模式,tarfile.open(data, "r")会自动识别压缩格式,当前参数是正确的。
内容的提问来源于stack exchange,提问作者Rose Vanilla
相关产品推荐
相关产品推荐

