我刚开始使用 Python,由于我的背景是更底层的语言(java、C++),所以我无法真正得到一些东西。
因此,在 python 中,可以创建一个文件变量,例如,通过打开一个文本文件,然后像这样遍历它的行:
f = open(sys.argv[1])
for line in f:
#do something
但是,如果我尝试f[0]
解释器给出错误。那么f
对象具有什么结构,我一般如何知道,如果我可以将for ... in ... :
循环应用于对象?
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)
,它将当前位置设置回文件的开头。
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 循环。或者换句话说,您从经验中了解哪些对象实现了迭代器协议。
在 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)
您正在寻找的是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
你能够做到这一点的原因是因为file object
它是一个可迭代的。
一旦你创建了 f,它就是一个文件对象。readlines 是文件对象的方法之一。这
for line in f.readlines():
启动一个循环,允许您编写的其他代码line
一次处理文件。您可以使用 for 循环,因为从 readlines() 返回的对象是可迭代的。
您可以随时使用 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']
解释器给出错误
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]
文件变量类似于 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()
,因为第一个在需要时读取行,第二个一次消耗所有行(大文件可能有问题)