Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.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中如何循环到EOF?_Python_Eof_Stringio - Fatal编程技术网

在Python中如何循环到EOF?

在Python中如何循环到EOF?,python,eof,stringio,Python,Eof,Stringio,我需要循环,直到找到一个类似文件的对象的结尾,但我没有找到“显而易见的方法”,这让我怀疑我忽略了什么,嗯,显而易见的。:-) 我有一个流(在本例中,它是一个StringIO对象,但我对一般情况也很好奇),它以“”格式存储未知数量的记录,例如: data = StringIO("\x07\x00\x00\x00foobar\x00\x04\x00\x00\x00baz\x00") 现在,我能想象的阅读这篇文章的唯一清晰方式是使用(我认为是)一个初始化的循环,这似乎有点不符合python: len

我需要循环,直到找到一个类似文件的对象的结尾,但我没有找到“显而易见的方法”,这让我怀疑我忽略了什么,嗯,显而易见的。:-)

我有一个流(在本例中,它是一个StringIO对象,但我对一般情况也很好奇),它以“”格式存储未知数量的记录,例如:

data = StringIO("\x07\x00\x00\x00foobar\x00\x04\x00\x00\x00baz\x00")
现在,我能想象的阅读这篇文章的唯一清晰方式是使用(我认为是)一个初始化的循环,这似乎有点不符合python:

len_name = data.read(4)

while len_name != "":
    len_name = struct.unpack("<I", len_name)[0]
    names.append(data.read(len_name))

    len_name = data.read(4)
len_name=data.read(4)
而len_name!="":

len_name=struct.unpack(“您见过如何迭代文本文件中的行吗

for line in file_obj:
  use(line)
您可以使用自己的生成器执行相同的操作:

def read_blocks(file_obj, size):
  while True:
    data = file_obj.read(size)
    if not data:
      break
    yield data

for block in read_blocks(file_obj, 4):
  use(block)
另见:


我发现,正如预测的那样,最典型和最流行的答案是使用非常专业的生成器“一次读取4个字节”。有时通用性并不难(也更值得;-),因此,我建议使用以下非常通用的解决方案:

import operator
def funlooper(afun, *a, **k):
  wearedone = k.pop('wearedone', operator.not_)
  while True:
    data = afun(*a, **k)
    if wearedone(data): break
    yield data
现在,您所需的循环头只是:funlooper中lenu name的
(data.read,4):

编辑:由于一条评论指责我的前一个版本(将退出测试硬编码为
如果不是数据:
)有“隐藏的依赖关系”,wearedone
的习惯用法变得更加通用了

通常的瑞士军刀循环,也很好,当然,像往常一样:

import itertools as it

for len_name in it.takewhile(bool, it.imap(data.read, it.repeat(4))): ...
或者,相当等价地:

import itertools as it

def loop(pred, fun, *args):
  return it.takewhile(pred, it.starmap(fun, it.repeat(args)))

for len_name in loop(bool, data.read, 4): ...

python中的EOF标记是一个空字符串,因此,如果不编写函数将其封装在迭代器中,您所拥有的非常接近您将获得的最佳值。我可以通过更改
while
以一种更加python的方式编写,如:

while len_name:
    len_name = struct.unpack("<I", len_name)[0]
    names.append(data.read(len_name))
    len_name = data.read(4)
while len_name:

len_name=struct.unpack(“我更喜欢前面提到的基于迭代器的解决方案,将其转换为for循环。另一个直接编写的解决方案是Knuth的“循环半”


通过比较,您可以看到它是如何轻松地提升到自己的生成器中并用作for循环的。

您可以将迭代与哨兵结合起来:

for block in iter(lambda: file_obj.read(4), ""):
  use(block)

我同意Tendayi关于函数和迭代器可读性的建议:

def read4():
    len_name = data.read(4)
    if len_name:
        len_name = struct.unpack("<I", len_name)[0]
        return data.read(len_name)
    else:
        raise StopIteration

for d in iter(read4, ''):
    names.append(d)
def read4():
len_name=data.read(4)
如果len_名称:

len_name=struct.unpack("您还可以在生成器中将循环构造为while循环。使用可读性最好的方法。虽然存在隐藏的依赖项,但由于funlooper要求函数返回非真结果以指示结束。@R.Pate,您当然可以简单地向funlooper添加一个默认为
运算符的
wearedone
谓词参数。不是_
并将
if
更改为
if wearedone(数据):break
——我只是觉得不值得用这个琐碎的代码进一步概括答案,因为我确信(而且是正确的;-)其他答案会过于专业化(毫无益处).啊,好吧,既然过度的专业化正在赢得这一天的胜利,让我编辑一下答案,以表明在这种情况下,通用性并没有变得更难(也更值得一试;-).我想你误解了我的意思:最初的funlooper太笼统了。因为我们已经依赖具有特定形式的返回值,所以在这里依赖类似文件的接口(read方法)的这一部分是合理的,而不是试图传递一个通用的可调用函数。如果失败,用户必须至少知道依赖关系。“Boolean false”不是“一种特定的形式”——它是一种非常通用的形式,许多种类的Python对象都可以满足。您对这个问题的两个答案之一(!),一个未被接受的,目前投票数最多的,和我原来的一样长和一般结构(按照正常的SO礼仪,我不会对一个问题给出很多答案!),所以它的极端专业化并没有带来任何好处。(你们中的另一个答案,被iter和sentinel接受的答案,更简洁——没有我的itertools那么笼统,但更简单)。如果你不同意它取决于返回值的特定形式,为什么你要更改答案?你认为依赖性的其他方式是什么?(我最初更喜欢你的答案。)绝对是最好的anwser。你让我在这一个,我忘记了这个非常有用的哨兵。我想我也最喜欢这一个;它的作用非常清楚,因为代码太少了。谢谢你的帮助!只是提醒你,如果你一直在写它,在迭代它之前,友好地回放文件,即file_obj.seek(0)。这需要在循环之前将赋值复制到len_name(您省略了),并且几乎总是希望避免这种重复。答案太多了!也许我不应该在午餐前发布。:-)在这种情况下,我想我喜欢
iter()
解决方案更好,但我觉得没有想到这一点很愚蠢。这是你应得的+1。-)哇。是的,iter()解决方案很好。再加上“lambda:”和闭包,这让理解起来有点困难,但绝对是甜蜜的。没有理由,只是我很快就拼凑起来的东西。我已经修改了这个片段。
def read4():
    len_name = data.read(4)
    if len_name:
        len_name = struct.unpack("<I", len_name)[0]
        return data.read(len_name)
    else:
        raise StopIteration

for d in iter(read4, ''):
    names.append(d)