Python 取消文件上的最后一行迭代
我需要对一个文件进行迭代,停止对某个条件的迭代,然后使用另一个函数在同一行继续解析该文件(这可能会发生变化,因此我不能只在前一个函数中添加内容) 示例文件(file.txt): 我尝试执行的功能:Python 取消文件上的最后一行迭代,python,python-3.x,for-loop,file-io,Python,Python 3.x,For Loop,File Io,我需要对一个文件进行迭代,停止对某个条件的迭代,然后使用另一个函数在同一行继续解析该文件(这可能会发生变化,因此我不能只在前一个函数中添加内容) 示例文件(file.txt): 我尝试执行的功能: def parse1(file, stop): # 1st parsing function (Main function I am doing) for line in file: if line.strip() == stop: # Stop
def parse1(file, stop):
# 1st parsing function (Main function I am doing)
for line in file:
if line.strip() == stop:
# Stop parsing on condition
break
else:
# Parse the line (just print for example)
print(line)
def parse2(file):
# 2nd parsing function (Will be my own functions or external functions)
for line in file:
# Parse the line (just print for example)
print(line)
导致终端:
>>> file = open("file.txt")
>>> parse1(file, "4")
1
2
3
>>> parse2(file)
5
6
7
8
9
我的问题是,当我查找条件时,第一个函数跳过了“4”行
如何避免这种情况:我找到了取消上一次迭代或返回一行的解决方案
file.tell()
函数不适用于文件上的for
我尝试在时使用+file.readline()
执行此操作,但它比for
在文件上循环的速度要慢得多(我想解析具有数百万行的文件)
是否有一个优雅的解决方案来保持for
循环的使用?在python3中,“for line In file”构造在内部由迭代器表示。根据定义,从迭代器生成的值不能“放回”供以后使用()
要获得所需的行为,您需要一个将两个迭代器链接在一起的函数,例如itertools
模块提供的函数。在parse1
的停止条件下,返回最后一行以及文件迭代器:
import itertools
def parse1(file,stop):
# 1st parsing function
for line in file:
# Stop parsing on condition
if line.strip() == stop:
return itertools.chain([line],file) # important line
else:
# Parse the line (just print for example)
print('parse1: '+line)
chain语句连接两个迭代器。第一个迭代器只包含一个元素:要再次处理的行。第二个迭代器是文件的剩余部分。一旦第一个迭代器的值用完,就会访问第二个迭代器
您不需要更改parse2
。为了清楚起见,我修改了打印语句:
def parse2(file):
# 2nd parsing function
for line in file:
# Parse the line (just print for example)
print('parse2: '+line)
然后,您可以以最实用的方式调用parse1和parse2:
with open('testfile','r') as infile:
parse2(parse1(infile,'4'))
上述行的输出为:
parse1: 1
parse1: 2
parse1: 3
parse2: 4
parse2: 5
parse2: 6
parse2: 7
parse2: 8
parse2: 9
注意,值“4”是如何由parse2
函数生成的。我建议对您的文件对象创建一个copy1,然后在else
块中迭代该副本,并在第一个函数中调用第二个函数,另外,作为一种更具python风格的方式,您可以使用with
语句打开文件,该文件将在语句末尾关闭文件,并将第二个函数放入第一个函数中:
#ex.txt
1
2
3
4
5
6
7
8
9
10
您可以使用创建文件对象的copy1:
from itertools import tee
def parse1(file_name, stop):
def parse2(file_obj):
print '**********'
for line in file_obj:
print(line)
with open(file_name) as file_obj:
temp,file_obj=tee(file_obj)
for line in temp:
if line.strip() == stop:
break
else:
next(file_obj)
print(line)
parse2(file_obj)
parse1("ex.txt",'4')
结果:
1
2
3
**********
4
5
6
7
8
9
10
1) 实际上,itertools.tee
并不创建副本,但您可以基于DOC将其用于此目的,它从单个iterable返回n个独立的迭代器。
您可以将其中一个独立迭代器分配给已迭代的对象本身,并将另一个迭代器创建为temp。
IMHO,最简单的解决方案是让第一个解析器返回找到停止条件的行,并将其传递给第二个解析器。第二个应具有解析一行的显式函数,以避免代码重复:
def parse1(file, stop):
# 1st parsing function (Main function I am doing)
for line in file:
if line.strip() == stop:
# Stop parsing on condition
return line
else:
# Parse the line (just print for example)
print(line)
return None
def parse2(file, line = None):
# 2nd parsing function (Will be my own functions or external functions)
def doParse(line):
# do actual parsing (just print for example)
print(line)
if line is None:
doParse(line)
for line in file:
doParse(line)
# main
...
stop = parse1(file)
if stop:
parse2(stop, file)
你能不能保留parse1中的line变量并将其传递给parse2这个想法对我自己的函数很好,但是我可以使用一些外部函数来代替没有类似参数的parse2
。谢谢,这正是我需要的!这个想法适用于我自己的函数,但如果我想使用一些外部函数来代替没有这样参数的parse2,就不要这样做。@Anc欢迎,我认为将函数放在一个函数中更有效、更安全!我同意只生成一个函数更有效,但对于我的情况,我需要灵活性(我想要解析的文件类型可能会有所不同)。
def parse1(file, stop):
# 1st parsing function (Main function I am doing)
for line in file:
if line.strip() == stop:
# Stop parsing on condition
return line
else:
# Parse the line (just print for example)
print(line)
return None
def parse2(file, line = None):
# 2nd parsing function (Will be my own functions or external functions)
def doParse(line):
# do actual parsing (just print for example)
print(line)
if line is None:
doParse(line)
for line in file:
doParse(line)
# main
...
stop = parse1(file)
if stop:
parse2(stop, file)