题
我需要循环直到我撞击端的一个类似文件的目的,但是我没找到"显而易见的方式这样做",这让我怀疑我是俯瞰着的东西,那么,显而易见的。:-)
我有一个流(在这种情况下,这是一个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)