【问题标题】:Using "with" statement for CSV files in Python在 Python 中对 CSV 文件使用“with”语句
【发布时间】:2010-10-01 06:22:51
【问题描述】:

是否可以将with 语句直接用于CSV 文件?能够做这样的事情似乎很自然:

import csv
with csv.reader(open("myfile.csv")) as reader:
    # do things with reader

但是 csv.reader 不提供 __enter____exit__ 方法,所以这不起作用。但是,我可以分两步完成:

import csv
with open("myfile.csv") as f:
    reader = csv.reader(f)
    # do things with reader

第二种方式是理想的方式吗?他们为什么不让 csv.reader 直接兼容 with 语句?

【问题讨论】:

  • 如下所述,对于 csv 阅读器来说,它真的没有意义。但它确实适用于作家!

标签: python csv with-statement


【解决方案1】:

with 语句的主要用途是对语句中使用的对象进行异常安全的清理。 with 确保关闭文件、释放锁、恢复上下文等。

csv.reader 是否有异常情况需要清理的东西?

我会选择:

with open("myfile.csv") as f:
    for row in csv.reader(f):
        # process row

csv.readerwith 语句一起使用不需要提交补丁。

import contextlib

模块contextlib中函数contextmanager的帮助:

contextmanager(func)
    @contextmanager decorator.

典型用法:

    @contextmanager
    def some_generator(<arguments>):
        <setup>
        try:
            yield <value>
        finally:
            <cleanup>

这就是:

    with some_generator(<arguments>) as <variable>:
        <body>

相当于这个:

    <setup>
    try:
        <variable> = <value>
        <body>
    finally:
        <cleanup>

这是我如何使用它的具体示例:curses_screen

【讨论】:

  • @J.F.Sebastion:我认为所有的“数据压缩”和“文件格式”库模块都应该直接支持。
  • @S.Lott:我同意标准库应该在适用的地方自己创建上下文管理器。对于csv 模块,它可能是reader = csv.open(path),但不是 reader = csv.reader(iterable)
  • @J.F. Sebastian +1 深入解释了如何使用 contextlib 来实现这一点,但请检查来自 @bluce 的响应以了解与 csv 一起使用的实际实现。
  • @technomalogical:这种实现只有在标准库中才有意义。 @bluce 的实现不能在 stdlib 中。它的界面过于简单(需要考虑一些事情:编码、缓冲、文件模式值的限制等)。它节省了 1 行代码,但界面复杂。
【解决方案2】:

是的。第二种方法是正确的。

为什么?谁知道。你是对的,这可能是一个简单的改变。它不像其他事情那样优先。

您可以轻松制作自己的补丁包并提交。

【讨论】:

  • 好吧,也许我会这样做。谢谢。
  • 我不确定这是一个“可修补的攻击”。 CSV 阅读器旨在作用于打开的文件对象并提供可迭代的行——没有真正的资源获取和释放。如果您想快速退出 with 块,请执行 rows = list(csv.reader(file_)) 并使用其外的行。
  • @cdleary:我认为对 with 的响应不必反映实际的资源使用,而只是类似于“资源”。所有“数据压缩”和“文件格式”库模块都应该这样做以保持简单的一致性。
【解决方案3】:

问题是 csv.reader 并没有真正管理上下文。它可以接受任何可迭代的,而不仅仅是文件。因此它不会在其输入上调用 close(顺便说一下,如果它调用了,您可以使用 contextlib.closure)。因此,对 csv.reader 的上下文支持实际上会做什么并不明显。

【讨论】:

    【解决方案4】:
    import csv
    
    class CSV(object):
        def __init__(self,path,mode):
            self.path = path
            self.mode = mode
            self.file = None
    
        def __enter__(self):
            self.file = open(self.path,self.mode)
            if self.mode == 'r':
                return csv.reader(self.file)
            elif self.mode == 'w':
                return csv.writer(self.file)
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.file.close()   
    
    with CSV('data.csv','r') as reader:
        for row in reader:
            print row
    

    【讨论】:

      【解决方案5】:

      使用生成器函数很容易创建您想要的内容:

      
      import csv
      from contextlib import contextmanager
      
      @contextmanager
      def opencsv(path):
         yield csv.reader(open(path))
      
      with opencsv("myfile.csv") as reader:
         # do stuff with your csvreader
      

      【讨论】:

      • 在异常情况下实际上并没有关闭文件。它使with 语句有效......但仅此而已。
      猜你喜欢
      • 2014-04-11
      • 1970-01-01
      • 1970-01-01
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-31
      • 1970-01-01
      相关资源
      最近更新 更多