【问题标题】:Pythonic way to ignore for loop control variable忽略循环控制变量的 Pythonic 方法
【发布时间】:2010-12-25 13:05:35
【问题描述】:

我正在编写的 Python 程序是从文件顶部读取一定数量的行,并且程序需要保留此标头以供将来使用。目前,我正在做类似以下的事情:

header = ''
header_len = 4
for i in range(1, header_len):
    header += file_handle.readline()

Pylint 抱怨我没有使用变量i。什么是更 Pythonic 的方式来做到这一点?

编辑:该程序的目的是智能地将原始文件拆分为更小的文件,每个文件都包含原始标题和数据的子集。因此,在读取文件的其余部分之前,我需要仅读取并保留标题。

【问题讨论】:

    标签: python


    【解决方案1】:
    f = open('fname')
    header = [next(f) for _ in range(header_len)]
    

    由于您要将标头写回新文件,因此您无需对其进行任何操作。要将其写回新文件:

    open('new', 'w').writelines(header + list_of_lines)
    

    如果您知道旧文件中的行数,list_of_lines 将变为:

    list_of_lines = [next(f) for _ in range(chunk_len)]
    

    【讨论】:

    • 直截了当,易于理解,并消除了 pylint 投诉。因此,这是最好的答案,IMO。
    • 您不想关闭新文件吗? ;)
    【解决方案2】:

    我不确定 Pylint 规则是什么,但您可以使用“_”一次性变量名。

    header = ''
    header_len = 4
    for _ in range(1, header_len):
        header += file_handle.readline()
    

    【讨论】:

    • 您不需要使用 for 循环。我推荐一个列表理解(见我下面的帖子)。不过,对一次性变量的调用很好。
    • @Roger Pate:你能解释一下吗?
    • @unknown,使用 for 循环没有错。 for 循环是 Python 不可或缺的一部分,是编程的基本概念。如果有人说不使用它,告诉他们去远足
    • 你每天都会学到一些新东西——我不知道 _ 变量。谢谢! +1
    【解决方案3】:
    import itertools
    
    header_lines = list(itertools.islice(file_handle, header_len))
    # or
    header = "".join(itertools.islice(file_handle, header_len))
    

    请注意,对于第一个,换行符仍然存在,以剥离它们:

    header_lines = list(n.rstrip("\n")
                        for n in itertools.islice(file_handle, header_len))
    

    【讨论】:

    • 如果去掉这些行,就很难回忆起原始标题的结构。我建议你保留它们。
    • 不,不会。在该示例中,它们存储在一个列表中,而不是一个长字符串中。他应该使用哪个取决于他以后对数据的处理方式。
    • OP 在他的脚本中写道 'header += ...' 所以我认为他的意思是一个字符串,但你是对的:这取决于。
    • Arrieta:这就是我使用单独的 header 和 header_lines 变量的原因。
    • Anurag:您自己的答案甚至不使用“for line in f”,我目前看到的任何答案也没有直接迭代文件——如果有的话,itertools 是这里唯一的解决方案将文件用作迭代器,因此是“for line in f”的最接近答案。
    【解决方案4】:

    我的最佳答案如下:

    文件 test.dat:

    This is line 1
    This is line 2
    This is line 3
    This is line 4
    This is line 5
    This is line 6
    This is line 7
    This is line 8
    This is line 9
    

    Python 脚本:

    f = open('test.dat')
    nlines = 4
    header = "".join(f.readline() for _ in range(nlines))
    

    输出:

    >>> header
    'This is line 1\nThis is line 2\nThis is line 3\nThis is line 4\n'
    

    请注意,您不需要调用任何模块;你也可以使用任何虚拟变量来代替_(它适用于i,或j,或ni,或其他),但我建议你不要(以避免混淆)。你可以去掉换行符(虽然我不建议你这样做——这样你可以区分行)或者做任何你可以用 Python 中的字符串做的事情。

    请注意,我没有提供打开文件的模式,所以它默认为“只读”——这不是 Pythonic;在 Python 中“显式优于隐式”。最后,好人关闭他们的文件;在这种情况下,它是自动的(因为脚本结束),但最好使用 f.close() 关闭它们。

    愉快的 Pythoning。

    编辑:正如 Roger Pate 所指出的,方括号在列表理解中是不必要的,从而将行减少了两个字符。原始脚本已被编辑以反映这一点。

    【讨论】:

    • 当您实际上不需要列表并且任何可迭代对象都可以工作时,例如此处的"".join 的参数,那么生成器表达式会更好,更容易(通过两次击键;)等等比列表理解更清晰:"".join(..) 而不是 "".join([..])。它们是相关的,LC 实际上是 genexp 的一个特例(至少在我看来),其中[..] 只是为list(..) 提供方便。 python.org/dev/peps/pep-0289
    • 是的,我读过。为了其他只想看代码不想看的人,我还是希望你关闭它。
    • @Arrieta:NASA 批准你使用他们的标志了吗? ;-p
    • 实际上在join 中,您必须使用列表推导而不是迭代器来提高性能;)
    【解决方案5】:

    可能是这样的:

    header_len = 4
    header = open("file.txt").readlines()[:header_len]
    

    但是,长文件会很麻烦。

    【讨论】:

    • .readlines() 读取整个文件,但是.. 如果您有一个大文件并且不想将整个内容读入内存,这可能是个坏主意
    • 是的,我补充说,当你写这篇文章的时候,;)
    • @david : guido 请让它变得懒惰 非常懒惰...stackoverflow.com/questions/519633/…
    • 没有必要了,现在我们有了itertools.islice
    • +1 为简单起见,OP 可以轻松使用剩余的列表项拆分成更小的文件。 readlines() 确实读取了整个文件,但我不会为此而对你进行-1,因为我们不知道 OP 的文件在 GB 范围内是否有那么大,所以 OP 使用这种方法可能仍然可以.
    【解决方案6】:

    我没有发现您的解决方案有任何问题,可能只是将 i 替换为 _,我也不喜欢在任何可以使用更简单解决方案的地方调用 itertools,就像人们使用 jQuery 来完成琐碎的 javascript 任务一样。无论如何,只是让 itertools 在这里报仇是我的解决方案

    既然你想逐行读取整个文件,为什么不先读取标题,然后做任何你想做的事情

    header = ''
    header_len = 4
    
    for i, line in enumerate(file_handle):
        if i < header_len:
            header += line
        else:
            # output chunks to separate files
            pass
    
    print header
    

    【讨论】:

      【解决方案7】:

      怎么样:

      header = []
      for i,l in enumerate(file_handle):
          if i <= 3: 
               header += l
               continue
          #proc rest of file here
      

      【讨论】:

        【解决方案8】:

        使用 _ 作为虚拟变量的一个问题是它只能在一个层面上解决问题,请考虑以下内容。

        def f(n, m):
        """A function to run g() n times and run h() m times per g."""
            for _ in range(n):
                g()
                for _ in range(m):
                    h()
            return 0
        

        这个函数工作正常,但是 m 次运行的 _ 迭代器是有问题的,因为它可能与上面的 _ 冲突。无论如何,PyCharm 都在抱怨这种语法。

        所以我认为 _ 并不像之前建议的那样“一次性”。

        也许您可能只想创建一个函数来完成它!

        def run(f, n, *args):
            """Runs f with the arguments from the args tuple n times."""
            for _ in range(n):
                f(*args)
        

        例如你可以这样使用它:

        >>> def ft(x, L):
        ...     L.append(x)
        
        >>> a = 7
        >>> nums = [4, 1]
        >>> run(ft, 10, a, nums)
        >>> nums
        [4, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]
        

        【讨论】:

          【解决方案9】:
          s=""
          f=open("file")
          for n,line in enumerate(f):
            if n<=3 : s=s+line
            else:
                # do something here to process the rest of the lines          
          print s
          f.close()
          

          【讨论】:

          • 他似乎想要一个字符串中的结果(注意他写了 header += ...)
          • 我认为这个实现对于这么简单的任务来说过于复杂了;它读起来像 Python 上的 C - 利用“包含电池”的理念并在对象上使用现有方法。
          • 过于复杂??你用什么标准来判断??代码的字符数?代码行数??包括电池??你在说我不使用哪种电池?你可以用数百万行测试我的代码和你的代码,它们的性能都相当。那么有什么关系呢?
          • “包含电池”是 Python 语言的座右铭(参见网站)“Python 爱好者使用短语“包含电池”来描述标准库”。我的意思是你的风格没有利用标准库,这样做是在重新发明轮子。这不符合 Python 的哲学。通过重新发明轮子,您会谴责其他人理解您的逻辑(在某些情况下这可能很困难):通过使用标准库,您可以在更高的抽象层次上表达您的想法,并且不会因轮子重新发明而分散您的代码逻辑。
          • 无需四处投反对票——这是一个学习的地方,你不会被别人评论你的代码冒犯。如果您受不了高温,请远离厨房。
          猜你喜欢
          • 1970-01-01
          • 2018-03-02
          • 2022-01-18
          • 2017-11-17
          • 2018-04-28
          • 2016-10-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多