如何解决csv.writer在with块中调用stdout时的__exit__属性错误?
解决
csv.writer无法直接用在with语句的问题 嘿,这个坑我之前踩过!咱们先搞清楚为啥报错:csv.writer对象本身不是上下文管理器——它没有__exit__方法,而with语句要求被管理的对象必须实现__enter__和__exit__这两个方法来处理资源的打开和清理,所以直接写with csv.writer(...) as file就会抛出AttributeError: __exit__。
下面给你几个Python里的优雅解决办法,类似Ruby里的简洁写法:
方案1:最规范的Pythonic写法(推荐)
把文件对象的上下文管理和csv.writer的创建分开,让with负责管好文件资源,csv.writer专注处理格式:
import csv import sys stdout = sys.stdout output = "your_output.csv" # 或者设为"stdout" with open(output, "w") if output != 'stdout' else stdout as file: writer = csv.writer(file) # 这里写你的写入逻辑 writer.writerow(["姓名", "年龄"]) writer.writerow(["张三", 25])
这种写法清晰又安全,with会自动帮你关闭磁盘文件(如果是stdout的话就不用关,毕竟是系统标准输出)。
方案2:自定义上下文管理器(封装成类似Ruby的块风格)
如果你想把csv.writer直接包装成可在with里用的对象,可以用contextlib.contextmanager写个简单的装饰器,把文件的打开、写入、关闭逻辑封装起来:
from contextlib import contextmanager import csv import sys stdout = sys.stdout @contextmanager def csv_writer(output): # 打开文件或者用stdout file = open(output, "w") if output != 'stdout' else stdout try: # 返回csv.writer对象给with语句使用 yield csv.writer(file) finally: # 只有磁盘文件需要关闭,别碰stdout! if output != 'stdout': file.close() # 使用起来就像直接管理csv.writer一样 with csv_writer("output.csv") as writer: writer.writerow(["col1", "col2"]) with csv_writer("stdout") as writer: writer.writerow(["hello", "from", "stdout"])
这个就和Ruby里自定义块的思路很像,把重复的逻辑封装起来,用的时候更简洁。
为啥前两种写法没问题?
你之前写的:
with (open(output, "w")) if output != 'stdout' else stdout as file:
和
file = csv.writer(open(output, "w") if output != 'stdout' else stdout)
第一种是with直接管理文件对象(open()返回的是上下文管理器),第二种是直接创建csv.writer但没用到with(不过注意第二种写法如果是磁盘文件的话,需要手动调用file.close(),不然可能会有资源泄漏)。
内容的提问来源于stack exchange,提问作者PapeK24
相关产品推荐
相关产品推荐

