假设我有一个像
gen = (i*2 for i in range(100))
我现在想创建一个包含生成器产生的所有值的字节对象。我可以执行以下操作:
b = bytes(gen)
我现在的问题是:自从
bytes
对象是不可变的,在这种情况下内存分配是如何工作的?我是否必须假设对于生成器产生的每个元素,都有一个新的 bytes
创建的对象,将先前的内容加上另一个元素复制到其中?这将是非常低效的,尤其是对于更大长度的发电机。而且由于生成器不提供任何长度信息,似乎没有任何其他方法可以在内部预先分配所需的内存。再说一次,用尽可能少的内存使用来实现这一目标的更好方法是什么?如果我使用(可变)
bytearray
首先并将其转换为 bytes
目的?b = bytes(bytearray(gen))
甚至是一个 list ?
b = bytes(list(gen))
但这看起来有点奇怪和违反直觉......
背景:我已经通过来自另一个模块(.pyd)的 C-API 一次读取一个字节(作为 0..255 中的 Python 整数)的特定生成器,并且序列的总长度事先已经知道,最多到 2**25 字节。我的读出函数应该收集这些并返回
bytes
对象,我认为这是合适的,因为数据是只读的。
最佳答案
bytes(iterator)
使用内部 C-API _PyBytes_FromIterator
从迭代器创建字节对象函数,使用特殊 _PyBytes_Writer
协议(protocol)。它在内部使用一个缓冲区,当它溢出时使用规则调整大小:
bufsize += bufsize / OVERALLOCATE_FACTOR
对于 linux OVERALLOCATE_FACTOR=4,对于 windows OVERALLOCATE_FACTOR=2。那些。这个过程看起来就像写入 RAM 中的文件。最后,缓冲区的内容返回。
关于来自生成器的 Python 字节对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46318527/