Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何循环使用同一打开文件的两个生成器_Python_Generator_Itertools - Fatal编程技术网

Python 如何循环使用同一打开文件的两个生成器

Python 如何循环使用同一打开文件的两个生成器,python,generator,itertools,Python,Generator,Itertools,我有一个中等大小的文件(25MB,1000000行),我想读取除第三行之外的每一行 第一个问题:将整个文件加载到内存中,然后读取行(方法.read()),还是一次加载并读取一行(方法.readline()) 由于我不是一名经验丰富的程序员,我尝试了itertools模块中的islice方法的第二个选项 import intertools with open(input_file) as inp: inp_atomtype = itertools.islice(inp, 0, 40, 3

我有一个中等大小的文件(25MB,1000000行),我想读取除第三行之外的每一行

第一个问题:将整个文件加载到内存中,然后读取行(方法
.read()
),还是一次加载并读取一行(方法
.readline()

由于我不是一名经验丰富的程序员,我尝试了
itertools
模块中的
islice
方法的第二个选项

import intertools

with open(input_file) as inp:
    inp_atomtype = itertools.islice(inp, 0, 40, 3)
    inp_atomdata = itertools.islice(inp, 1, 40, 3)
    for atomtype, atomdata in itertools.zip_longest(inp_atomtype, inp_atomdata):
        print(atomtype + atomdata)
虽然通过单个生成器(
inp_atomtype
inp_atomdata
)循环打印正确的数据,但同时通过这两个生成器循环(如本代码所示)打印错误的数据


第二个问题:如何使用生成器到达所需的行?

您不需要对迭代器进行切片,一个简单的行计数器就足够了:

with open(input_file) as f:
    current_line = 0
    for line in f:
        current_line += 1
        if current_line % 3:  # ignore every third line
            print(line)  # NOTE: print() will add an additional new line by default
至于把它变成一个生成器,只需
产生
行,而不是打印


说到速度,考虑到您无论如何都要读取行,I/O部分可能会采取相同的措施,但您可能会受益一点(总处理时间)如果您有足够的工作内存来保存文件内容,并且可以预先加载整个文件而不是流式处理,则可以使用快速列表切片而不是计算行数。

q2:这是我的生成器:

def yield_from_file(input_file):
    with open(input_file) as file:
        yield from file

def read_two_skip_one(gen):
    while True:
        try:
            val1 = next(gen)
            val2 = next(gen)
            yield val1, val2
            _ = next(gen)
        except StopIteration:
            break

if __name__ == '__main__':
    for atomtype, atomdata in read_two_skip_one(yield_from_file('sample.txt')):
        print(atomtype + atomdata)
sample.txt是用一个bash shell生成的(它只是一行,计数到100)

关于q1:如果要多次读取该文件,最好将其保存在内存中。否则你可以逐行阅读

关于您遇到的错误结果问题:

两个
itertools.islice(inp,0,40,3)
语句都将
inp
用作生成器。两者都将调用
next(inp)
,为您提供一个值。
每次在迭代器上调用
next()
,它都会更改其状态,因此这就是问题的根源。

第一个问题:我非常确定.readline()比.read()快。另外,基于我的测试的最快方法是进行裁剪,如:

with open(file, 'r') as f:
    for line in f:
        ...
第二个问题:我对此不太确定。你可以考虑使用产量。 您可以参考以下代码片段:

def myreadlines(f, newline):
    buf = ""
    while True:
        while newline in buf:
            pos = buf.index(newline)
            yield buf[:pos]
            buf = buf[pos + len(newline):]
        chunk = f.read(4096)

        if not chunk:
        # the end of file
            yield buf
            break
        buf += chunk

with open("input.txt") as f:
    for line in myreadlines(f, "{|}"):
        print (line)

yield
非常适合这一点

此函数从iterable生成对,并每三个项跳过一次:

def two_thirds(seq):
    _iter = iter(seq)
    while True:
        yield (next(_iter), next(_iter))
        next(_iter)
您将丢失一半对,这意味着
三分之二(范围(2))
将立即停止迭代

您还可以从中使用石斑鱼配方,并忽略生成的每个元组中的第三项:

for atomtype, atomdata, _ in grouper(lines, 3):
    pass

可以使用生成器表达式:

with open(input_file, 'r') as f:
    generator = (line for e, line in enumerate(f, start=1) if e % 3)
enumerate
将行号添加到每一行,而
if
子句忽略可被3整除的行号(默认编号从0开始,因此必须指定
start=1
,以获得所需的模式)


请记住,您只能在文件仍处于打开状态时使用生成器。

听起来像是一个x y问题,您想解决什么?根据
atomtype
的值,我想正确处理
atomdata
变量。您可以调用
next(gen)
,而无需将其分配给
我知道,这是一个习惯:D一些linter抱怨没有使用值。这是一个简单的解决方案,我可以同时访问这两个变量。
with open(input_file, 'r') as f:
    generator = (line for e, line in enumerate(f, start=1) if e % 3)