【问题标题】:Python file variable - what is it?Python 文件变量 - 它是什么?
【发布时间】:2013-05-19 17:38:33
【问题描述】:

我刚开始使用 Python,由于我的背景是更底层的语言(java、C++),所以我真的无法得到一些东西。

因此,在 python 中,可以创建一个文件变量,例如,通过打开一个文本文件,然后像这样遍历它的行:

f = open(sys.argv[1])
for line in f:
    #do something

但是,如果我尝试f[0],解释器会出错。那么f 对象具有什么结构,我一般如何知道,如果我可以将for ... in ... : 循环应用于对象?

【问题讨论】:

    标签: python file for-loop


    【解决方案1】:

    f 是一个file object。文档列出了它的结构,所以我只解释索引/迭代行为。

    只有实现__getitem__ 的对象才可索引,您可以通过调用hasattr(f, '__getitem__') 或仅调用f[0] 来检查它是否会引发错误。事实上,这正是你的错误信息告诉你的:

    TypeError: 'file' object has no attribute '__getitem__'
    

    文件对象不可索引。你可以调用f.readlines() 并返回一个行列表,它本身是可索引的。

    实现__iter__ 的对象可以使用for ... in ... 语法进行迭代。现在实际上有两种类型的可迭代对象:容器对象和迭代器对象。迭代器对象实现了两种方法:__iter____next__。容器对象仅实现 __iter__ 并返回一个迭代器对象,这实际上是您正在迭代的对象。文件对象是它们自己的迭代器,因为它们实现了这两种方法。

    如果你想在一个迭代中获取下一项,你可以使用next()函数:

    first_line = next(f)
    second_line = next(f)
    next_line_that_starts_with_0 = next(line for line in f if line.startswith('0'))
    

    请注意:可迭代对象通常不是“可回退的”,因此一旦您完成可迭代对象,就无法真正返回。要“倒回”文件对象,您可以使用f.seek(0),它将当前位置设置回文件的开头。

    【讨论】:

      【解决方案2】:

      1) f 不是一个列表。是否有任何书籍、教程或网站告诉您 f 是列表?如果不是,您为什么认为可以将 f 视为列表?您当然不能将 C++ 或 Java 中的文件视为数组,可以吗?为什么不呢?

      2) 在python中,for循环做了以下事情:

      a) The for loop calls __iter__() on the object to the right of 'in', 
         e.g. f.__iter__(). 
      
      b) The for loop repeatedly calls next() (or __next__() in python 3) on whatever 
         f.__iter__() returns.
      

      所以f.__iter__() 可以返回一个对象,以便在调用 next() 时执行它想做的任何事情。碰巧 Guido 决定 f.__iter__() 返回的对象应该在调用其 next() 方法时提供文件中的行。

      我怎么知道一般情况下,如果我可以申请 ... in ... :循环到一个 对象?

      如果对象具有__iter__() 方法,并且__iter__() 方法返回具有next() 方法的对象,则可以对其应用for-in 循环。或者换句话说,您从经验中了解哪些对象实现了迭代器协议

      【讨论】:

        【解决方案3】:

        这展示了sequence typeiterator type 之间的区别,sequence type 支持索引、切片和有限迭代,而iterator type 不支持索引或切片,但更高级的迭代,维护内部状态来执行它。

        文件对象是后者的一个例子。正如其他人指出的那样,您可以通过readlines 方法将内容提取为行并将它们存储在序列类型(特别是列表)中。

        【讨论】:

          【解决方案4】:

          在 Python 中,每个数据项都是一个 Python 对象。所以open()返回给你的都是一个对象;具体来说,是一个file对象,代表一个文件句柄。

          您已经知道如何做到这一点:

          handle = open("some_file.txt, "r")
          

          从概念上讲,这与 C 中的等价物非常相似:

          FILE *handle;
          
          handle = fopen("some_file.txt", "r");
          

          在 C 中,您可以对 handle 变量做的唯一有用的事情是将其传递给像 fread() 这样的调用。在 Python 中,对象具有与之关联的方法函数。所以,这里是 C 从文件中读取 100 个字节然后关闭它:

          FILE *handle;
          
          handle = fopen("some_file.txt", "r");
          result = fread(buffer, 1, 100 handle);  // read 100 bytes into buffer
          fclose(handle);
          

          这里是等效的 Python:

          handle = open("some_file.txt", "r");
          handle.read(100)
          handle.close()
          

          了解更多关于 Python 函数和对象的好方法是在 Python 提示符下使用内置的help() 命令。试试help(open),它并没有告诉你太多,但确实告诉你它返回了一个文件对象。那么试试help(file),现在你会得到很多信息。您可以阅读有关.close() 方法、.read() 以及诸如.readlines() 等其他方法的信息。

          但让您感到困惑的是迭代句柄对象。由于一个非常常见的情况是从文件中读取行,Python 使文件句柄作为 迭代器 工作,并且当您迭代时,您一次从文件中获取一行。

          Python 中的列表对象是 indexableiterable,所以如果你有一个名为 a 的列表,你可以同时使用 a[i]for x in a:。按位置查找项目a[i] 是索引。文件句柄对象不支持索引但支持迭代。

          在此处的几个答案中,您将看到 with 声明。这是 Python 中的最佳实践。 with 语句仅适用于 Python 中的某些类型的对象;对象必须支持几个特殊的方法函数。关于with,您现在真正需要知道的是,当您可以使用它时,可以为您完成一些必要的初始化和完成工作。在打开文件的情况下,with 语句将负责为您关闭文件。最重要的是with 语句保证即使代码引发异常也会完成最终确定。

          这是上述示例的惯用 Python:

          with open("some_file.txt") as handle:
              buffer = handle.read(100)
          

          【讨论】:

            【解决方案5】:

            你要找的是readlineshttp://docs.python.org/2/library/stdtypes.html#file.readlines

            file_lines = f.readlines()
            
            for line in file_lines:
                print line
            
            print file_lines[0] # You can access an element by index
            

            【讨论】:

            • .readlines() 的缺点是您将整个文件存储在内存中,这并不总是可行的。
            • 对,但这是获得对文件行的索引级访问的最直接方法,正如 OP 询问 f[0]
            【解决方案6】:

            之所以能够这样做是因为file object 是一个可迭代对象。

            【讨论】:

              【解决方案7】:

              文件变量类似于 C 中的文件处理程序。您打开它,对其进行操作(读取、写入)并最终关闭。

              handler.read() # read all file content at once
              
              handler.write(blob) # write there something
              
              handler.readlines() # read list with lines
              
              for line in handler:
                  print line # iterate lines nicely
              

              最后一个例子比 for line in handler.readlines() 好,因为第一个在需要时读取行,第二个一次消耗所有行(对于大文件可能会出现问题)

              【讨论】:

                【解决方案8】:

                你总是可以使用 dir(f) 来查看 f 的结构,f 是一个文件对象

                 ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']
                

                【讨论】:

                  【解决方案9】:

                  解释器给出错误

                  TypeError: 'file' object has no attribute '__getitem__'
                  

                  它告诉你file 类型不允许像f[0] 这样的索引等等。如果一个类型具有属性__getitem__,它允许索引,否则不允许。如果是文件,则为后者。

                  你可以通过做更多地了解文件。

                  >>> fileTest = open('fileName')
                  >>> type(fileTest)
                  <type 'file'>
                  >>> dir(fileTest)
                  ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']
                  

                  for 循环通常可以应用于任何可迭代的结构。

                  如果你想要一个行列表,那么你可以这样做。

                  >>> with open('fileName') as f:
                           lines = f.readlines()
                  

                  或者通过做,

                  >>> with open('fileName') as f:
                           lines = [line for line in f]
                  

                  【讨论】:

                    【解决方案10】:

                    一旦你创建了 f,它就是一个文件对象。 readlines 是文件对象的方法之一。

                    for line in f.readlines():

                    启动一个循环,允许您编写的其他代码一次处理文件的line。您可以使用 for 循环,因为从 readlines() 返回的对象是可迭代的。

                    【讨论】:

                    • 要使这个答案起作用f 不需要是可迭代的。只有f.readlines() 返回的对象。最终,两个对象都是可迭代的,但这不是重点。
                    猜你喜欢
                    • 1970-01-01
                    • 2012-11-11
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-12-18
                    • 2011-09-03
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多