我遇到了两个版本的代码,它们都可以完成相同的任务,但代码本身有一点点不同:
with open("file") as f:
for line in f:
print line
Run Code Online (Sandbox Code Playgroud)
和
with open("file") as f:
data = f.readlines()
for line in data:
print line
Run Code Online (Sandbox Code Playgroud)
我的问题是,文件对象f默认情况下是列表data吗?如果没有,为什么第一块代码有效?哪个版本更好的做法?
Mac*_*Gol 11
Fileobject不是list- 它是一个符合迭代器接口(docs)的对象.即它实现__iter__了返回迭代器对象的方法.这迭代器对象同时实现了__iter__与next允许对集合迭代方法.
碰巧File对象是它自己的迭代器(docs)意味着file.__iter__()返回self.
双方for line in file并lines = file.readlines()在它们产生相同的结果,如果使用了获取/迭代器相当于所有文件中的行.但是,file.next() 缓冲文件中的内容(它会提前读取)以加快过程,有效地将文件描述符移动到比最后一行结束的位置更精确或更远的位置.这意味着如果您已经使用过for line in file,读取一些行并停止迭代(您没有到达文件的末尾)并且现在调用file.readlines(),则返回的第一行可能不是for循环迭代的最后一行之后的完整行.
当你使用 for x in my_it,口译员会打电话my_it.__iter__().现在,next()正在对前一次调用返回的对象调用该方法,并且对于每个调用,它的返回值都被分配给x.当next()提高StopIteration,循环结束.
注意:有效的迭代器实现应该确保一旦StopIteration引发,它应该保持为所有后续调用的上升next().
在这两种情况下,您都会逐行获取文件.方法不同.
使用您的第一个版本:
with open("file") as f:
for line in f:
print line
Run Code Online (Sandbox Code Playgroud)
当您逐行处理文件时,文件内容不会完全驻留在内存中(除非它是1行文件).
在开放的内置函数返回一个文件对象 -不是一个列表.该对象支持迭代; 在这种情况下,返回单个字符串,这些字符串是文件中的每组字符,由回车符或文件结尾终止.
你可以编写一个类似于幕后工作的循环for line in f: print line:
with open('file') as f:
while True:
try:
line=f.next()
except StopIteration:
break
else:
print line
Run Code Online (Sandbox Code Playgroud)
随着第二个版本:
with open("file") as f:
data = f.readlines() # equivelent to data=list(f)
for line in data:
print line
Run Code Online (Sandbox Code Playgroud)
您正在使用文件对象(file.readlines())的方法,该方法将整个文件内容作为各行的列表读入内存.然后代码在该列表上进行迭代.
您也可以编写类似的版本,突出显示引擎下的迭代器:
with open('file') as f:
data=list(f)
it=iter(data)
while True:
try:
line=it.next()
except StopIteration:
break
else:
print line
Run Code Online (Sandbox Code Playgroud)
在这两个示例中,您使用for循环来循环序列中的项目.每种情况下的项目相同(文件的各行)但基础序列不同.在第一个版本中,序列是文件对象; 在第二个版本中它是一个列表.如果您只想处理每一行,请使用第一个版本.如果需要行列表,请使用第二个.
阅读Ned Batchelder 关于循环和迭代的优秀概述.