5

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

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

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

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

4

10 回答 10

8

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

一个对象只有在实现时才是可索引的__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),它将当前位置设置回文件的开头。

于 2013-05-19T17:47:19.203 回答
4

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 决定 a 返回的对象f.__iter__()应该在调用 next() 方法时提供文件中的行。

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

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

于 2013-05-19T17:44:45.163 回答
2

在 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 中的列表对象既可索引又可迭代,因此如果您有一个名为的列表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)
于 2013-05-19T18:05:31.000 回答
2

这演示了支持索引、切片和有限迭代的序列类型与不支持索引或切片但更高级的迭代的迭代器类型之间的区别,它维护内部状态来执行此操作

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

于 2013-05-19T17:51:53.540 回答
1

您正在寻找的是readlines http://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
于 2013-05-19T17:41:30.290 回答
1

你能够做到这一点的原因是因为file object它是一个可迭代的。

于 2013-05-19T17:43:30.940 回答
0

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

for line in f.readlines():

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

于 2013-05-19T17:43:47.487 回答
0

您可以随时使用 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']
于 2013-05-19T17:45:34.377 回答
0

解释器给出错误

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]
于 2013-05-19T17:45:54.420 回答
0

文件变量类似于 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(),因为第一个在需要时读取行,第二个一次消耗所有行(大文件可能有问题)

于 2013-05-19T17:41:49.807 回答