Python 如何将iterable转换为流?
如果我有一个包含字符串的iterable,有没有简单的方法将其转换为流?我想这样做:Python 如何将iterable转换为流?,python,stream,iterator,Python,Stream,Iterator,如果我有一个包含字符串的iterable,有没有简单的方法将其转换为流?我想这样做: def make_file(): yield "hello\n" yield "world\n" output = tarfile.TarFile(…) stream = iterable_to_stream(make_file()) output.addfile(…, stream) 起点: class iterable_to_stream: def __init__(self,
def make_file():
yield "hello\n"
yield "world\n"
output = tarfile.TarFile(…)
stream = iterable_to_stream(make_file())
output.addfile(…, stream)
起点:
class iterable_to_stream:
def __init__(self, iterable):
self.iter = iter(iterable)
def read(self):
try:
return self.iter.next()
except StopIteration:
return ""
TarFile接受提供的任何内容--因此您可以使用(如果您使用的是Python 3.X)生成所需的内容
TarFile.addfile()
,或者您可以创建自己的类来提供并生成所需的内容。因为看起来没有“标准”的方法,我已经完成了一个简单的实现:
class iter_to_stream(object):
def __init__(self, iterable):
self.buffered = ""
self.iter = iter(iterable)
def read(self, size):
result = ""
while size > 0:
data = self.buffered or next(self.iter, None)
self.buffered = ""
if data is None:
break
size -= len(data)
if size < 0:
data, self.buffered = data[:size], data[size:]
result += data
return result
类iter\u到\u流(对象):
定义初始值(自,可编辑):
self.buffered=“”
self.iter=iter(iterable)
def读取(自身,大小):
result=“”
当大小>0时:
数据=self.buffered或next(self.iter,无)
self.buffered=“”
如果数据为无:
打破
大小-=长度(数据)
如果尺寸小于0:
数据,自缓冲=数据[:大小],数据[大小:]
结果+=数据
返回结果
这是我的流式迭代器,它是通过iterables支持流式分块请求的一个实验分支:
class IterStreamer(object):
"""
File-like streaming iterator.
"""
def __init__(self, generator):
self.generator = generator
self.iterator = iter(generator)
self.leftover = ''
def __len__(self):
return self.generator.__len__()
def __iter__(self):
return self.iterator
def next(self):
return self.iterator.next()
def read(self, size):
data = self.leftover
count = len(self.leftover)
if count < size:
try:
while count < size:
chunk = self.next()
data += chunk
count += len(chunk)
except StopIteration:
pass
self.leftover = data[size:]
return data[:size]
类IterStreamer(对象):
"""
类文件流迭代器。
"""
定义初始化(自身,生成器):
self.generator=generator
self.iterator=iter(生成器)
self.leftover=“”
定义(自我):
返回自生成器。\uuuu len\uuuuu()
定义(自我):
返回自迭代器
def next(自我):
返回self.iterator.next()
def读取(自身,大小):
数据=自身剩余
计数=长度(自身剩余)
如果计数<大小:
尝试:
当计数<大小时:
chunk=self.next()
数据+=块
计数+=len(块)
除停止迭代外:
通过
self.leftover=数据[大小:]
返回数据[:大小]
具有上下文的源:
相关单元测试:
>这段代码并没有使它进入稳定的分支,但是由于没有大量的块请求得到了很好的支持,但是它应该是你要做的一个很好的基础。有关如何使用它的示例,请参见源链接
Python3已经()了,取代了旧的类似文件的对象协议。(模块中的Python2中也提供了新的API,它与类文件对象协议向后兼容。) ,在Python 2和3中:import io
def iterable_to_stream(iterable, buffer_size=io.DEFAULT_BUFFER_SIZE):
"""
Lets you use an iterable (e.g. a generator) that yields bytestrings as a read-only
input stream.
The stream implements Python 3's newer I/O API (available in Python 2's io module).
For efficiency, the stream is buffered.
"""
class IterStream(io.RawIOBase):
def __init__(self):
self.leftover = None
def readable(self):
return True
def readinto(self, b):
try:
l = len(b) # We're supposed to return at most this much
chunk = self.leftover or next(iterable)
output, self.leftover = chunk[:l], chunk[l:]
b[:len(output)] = output
return len(output)
except StopIteration:
return 0 # indicate EOF
return io.BufferedReader(IterStream(), buffer_size=buffer_size)
用法示例:
with iterable_to_stream(str(x**2).encode('utf8') for x in range(11)) as s:
print(s.read())
对一位伟人的答案稍加修改。这里,
readinto(b)
实现对底层迭代器进行多次调用,以便根据给定的可写字节大小(如objectb
)收集尽可能多的字节
类迭代器Reader(io.RawIOBase):
定义初始化(self,迭代器):
self.iterator=迭代器
self.leftover=[]
def readinto(自身,缓冲区:bytearray)->可选[int]:
大小=长度(缓冲区)
而len(自身剩余)<尺寸:
尝试:
self.leftover.extend(下一步(self.iterator))
除停止迭代外:
打破
如果len(自身剩余)==0:
返回0
输出,self.leftover=self.leftover[:size],self.leftover[size:]
缓冲器[:len(输出)]=输出
返回透镜(输出)
def可读(自)->bool:
返回真值
使用方法:
def iterator1():
for i in ('a', 'b', 'c', 'd', 'e', 'f', 'g'):
res = i * 3
yield res.encode("utf8")
iterreader = IteratorReader(iterator1())
while True:
r = iterreader.read(4)
if not r:
break
print(r)
我对streams不太了解,但是你想要
stream=io.StringIO(“.”.join(make_file())
?不,我不想要make_file()
可能会返回一个大文件,我不想将其加载到内存中。有趣的链接:@TokenMacGuy:对不起,我不认为我看到了该链接的重要性…对-但是有没有办法通过StringIO流式传输迭代器?在将输入文件写入StringIO之前,我不希望将整个输入文件加载到内存中。@David——据我所知,不是这样。我想给你一个例子,围绕着StringIO
包装一个类,但看起来你已经得到了你所需要的:-)嗯…而这肯定会自行爆炸(如果next(iter)
返回”
?如果有人胆敢将一个大小传递给read(…)
)…我想我可以用一个BufferedReader
来处理这些细节…对不起,伙计,这似乎不可行。BufferedReader需要一个RawIOBase
的实例,而这离实现该接口还差得远……而且它甚至没有实现基本的流API(例如,read()
不接受大小)@David Wolever:似乎为您的iterable编写一个类似于RawIOBase
的包装器并将其传递给BufferReader
是可行的RawIOBase
对象只有4个方法,您可能只需要实现3个read…()
方法就可以了。这有一个bug,它将永远继续发出最后一个剩余的数据位。将pass
替换为return data
,bug就消失了。否。将pass
换成self.leftover='';返回数据
错误就消失了。修复了你们提到的错误。很抱歉没有响应,很长时间没有注意到Stackoverflow的通知。:)read
仍然有一个陈旧的遗留错误,通过2020年的差异和Python 3.8中的更改得到修复,这仍然是最好的方法吗?试过了,它仍然有效,但也许可以简化?