【问题标题】:python style question around reading small files关于读取小文件的python风格问题
【发布时间】:2011-01-12 00:43:46
【问题描述】:

在命名文件中读取最pythonic的方法是什么,去除空行、仅包含空格或将#作为第一个字符,然后处理剩余的行?假设这一切都可以轻松地存储在内存中。

注意:做到这一点并不难——我要的是最pythonic的方式。我已经写了很多 Ruby 和 Java,但已经失去了感觉。

这是一个稻草人:

file_lines = [line.strip() for line in open(config_file, 'r').readlines() if len(line.strip()) > 0]
for line in file_lines:
  if line[0] == '#':
    continue
  # Do whatever with line here.

我对简洁感兴趣,但不以变得难以阅读为代价。

【问题讨论】:

  • 所以应该去掉前导/尾随空格的行?
  • 只是空格,还是任何空格?
  • @Kevin,您的文字与您的代码不太匹配。你说你会用“#”作为第一个字符来剥离行(顺便说一句,那是前剥离还是后剥离?)但你没有说你会丢弃这些行......但你的示例代码确实跳过了它们.
  • +1 表示使用“简洁”。直到我查到它才认为这是一个真实的词。

标签: python coding-style idioms


【解决方案1】:

我会用这个:

processed = [process(line.strip())
             for line in open(config_file, 'r')
             if line.strip() and not line.strip().startswith('#')]

我在这里看到的唯一丑陋就是所有的重复剥离。去掉它会使函数有点复杂:

processed = [process(line)
             for line in (line.strip() for line in open(config_file, 'r'))
             if line and not line.startswith('#')]

【讨论】:

    【解决方案2】:
    for line in open("file"):
        sline=line.strip()
        if sline and not sline[0]=="#" :
           print line.strip()
    

    输出

    $ cat file
    one
    #
      #
    
    two
    
    three
    $ ./python.py
    one
    two
    three
    

    【讨论】:

    • 你使用not foo == bar而不是foo != bar的任何原因?
    【解决方案3】:

    文件很小,所以性能不是问题。我会追求清晰而不是简洁:

    fp = open('file.txt')
    for line in fp:
        line = line.strip()
        if line and not line.startswith('#'):
            # process
    fp.close()
    

    如果需要,可以将其包装在一个函数中。

    【讨论】:

      【解决方案4】:

      这符合描述,即

      剥离空的线, 仅包含空格,或将 # 作为 第一个字符,然后处理 剩余行数

      因此,以空格开头或结尾的行可以不受限制地通过。

      with open("config_file","r") as fp:
          data = (line for line in fp if line.strip() and not line.startswith("#"))
          for item in data:
              print repr(item)
      

      【讨论】:

      • 您需要在生成器中剥离line 两次——返回和startswith 检查。使用with 的道具。
      • @Max,如果您严格阅读要求,实际情况并非如此。他说“或将 # 作为第一个字符”(即不是第一个非空白)。他可能对后一种解释更满意,但 gnibbler 的回答是正确的。
      • 对。我取消了问题中的代码,这在两种情况下都会剥离。
      【解决方案5】:

      生成器非常适合此类任务。它们是可读的,保持完美的关注点分离,并且在内存使用和时间方面效率很高。

      def RemoveComments(lines):
          for line in lines:
              if not line.strip().startswith('#'):
                  yield line
      
      def RemoveBlankLines(lines):
          for line in lines:
              if line.strip():
                  yield line
      

      现在将这些应用到您的文件中:

      filehandle = open('myfile', 'r')
      for line in RemoveComments(RemoveBlankLines(filehandle)):
          Process(line)
      

      在这种情况下,很明显两个生成器可以合并为一个,但我将它们分开以展示它们的可组合性。

      【讨论】:

      • 生成器表达式会更加 Pythonic,特别是因为问题特别要求简洁。
      • 它清晰、简单、易于判断它的作用和易于测试。
      【解决方案6】:
      lines = [r for r in open(thefile) if not r.isspace() and r[0] != '#']
      

      字符串的.isspace() 方法是迄今为止测试字符串是否完全是空白的最佳方法——不需要像len(r.strip()) == 0 (ech;-) 这样的扭曲。

      【讨论】:

      • 很好,我不知道 isspace。
      • "".isspace() 返回 False,但 r 将始终至少有一个换行符
      • @gnibbler,不过要小心......在这里工作正常,因为这些行都是换行符终止的(或非空的,即使它没有正确终止,最后一行也会是)。如果不是,这将不起作用,因为 isspace() 为空字符串返回 False
      • 是的,在不同的情况下(可能存在空字符串——不适用于实际问题),您可能必须使用r and not r.isspace() 来排除空字符串和全空白字符串。但不适用于 this 问题;-)。
      【解决方案7】:

      使用稍新的习语(或使用 Python 2.5 from __future__ import with)您可以做到这一点,它的优点是安全清理,但非常简洁。

      with file('file.txt') as fp:
          for line in fp:
              line = line.strip()
              if not line or line[0] == '#':
                  continue
      
              # rest of processing here
      

      请注意,首先删除行意味着检查“#”实际上会拒绝作为第一个非空白的行,而不仅仅是“作为第一个字符”。如果您对此要求严格,很容易修改。

      【讨论】:

        【解决方案8】:

        我喜欢 Paul Hankin 的想法,但我会采取不同的做法:

        from itertools import ifilter, ifilterfalse, imap
        
        with open(r'c:\temp\testfile.txt', 'rb') as f:
            s1 = ifilterfalse(str.isspace, f)
            s2 = ifilter(lambda x: not x.startswith('#'), s1)
            s3 = imap(str.rstrip, s2)
            print "\n".join(s3)
        

        如果我担心内存使用情况,我可能只会这样做,而不是使用此处建议的一些更明显的方法。我可能会定义一个 iscomment 函数来消除 lambda。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-07
          • 1970-01-01
          相关资源
          最近更新 更多