我需要循环直到我撞击端的一个类似文件的目的,但是我没找到"显而易见的方式这样做",这让我怀疑我是俯瞰着的东西,那么,显而易见的。:-)

我有一个流(在这种情况下,这是一个StringIO对象,但是我很好奇有关的一般情况),它存储的一个未知数的记录"<length><data>"格式,例如:

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)

在一个C类的语言,我只是坚持的 read(4)while's试条款,但是当然这不会的工作蟒蛇。任何想法在一个更好的方式来做到这一点?

有帮助吗?

解决方案

可以通过 ITER()与前哨的结合迭代:

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

其他提示

你有没有看到如何迭代过在线文本的文件?

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)

参见:

我更喜欢已经提到的基于迭代器的溶液以变成一个for循环。直接写入另一种解决方案是Knuth的“环式 - 和半”

while 1:
    len_name = data.read(4)
    if not len_name:
        break
    names.append(data.read(len_name))

您可以通过比较这让您轻松地悬挂到自己的发电机,并作为一个for循环见。

我看到的,所预测的,即典型的,最流行的答案是使用非常专业的发电机,以“一次读取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

现在您所希望的环路头只是:for len_name in funlooper(data.read, 4):

修改:做出更一般由wearedone成语,因为评论指责我略低于一般前一版本(硬编码的出口检验为if not data:),其具有的一切事物“的隐藏依赖”的! - )

的循环, itertools

在通常的瑞士军刀,是太细,的当然,像往常一样:

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标记是一个空字符串,所以你有什么是相当接近你会得到最好不写一个函数在一个iterator来包装这件事。我可以通过改变while等被写入多一点Python的方式:

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

我会去与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)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top