【问题标题】:Python 3: Generate byte stream using 'with'Python 3:使用“with”生成字节流
【发布时间】:2017-07-07 21:08:06
【问题描述】:

我想做的是生成一个任意长度的字节流。这样做的原因是因为我需要生成一个任意大小的文件。 (对于某些背景,我尝试流式传输稀疏文件但 had trouble when the file sizes were large,因此我尝试动态生成字节。)

我一直在阅读文档以使对象与 with 一起工作,我正在努力正确地做到这一点。这是我在反复试验后一直在尝试的方法,但仍然无法正常工作。我想我错过了一些东西,但老实说,我不知道是什么。

class BinaryGenerator:
    def __init__(self, size_in_mbs):
        self.size_in_mbs = size_in_mbs

    def __enter__(self):
        yield self.__bytes_generator__(self.size_in_mbs)
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

    @staticmethod
    def __bytes_generator__(mega_bytes):
        for i in range(mega_bytes * 1024):
            yield b'\x00'

def __write_size__(size):
    with open('arbitrary-{}mb.bin'.format(size), 'wb') as file:
        with BinaryGenerator(size) as binary:
            file.write(binary)


if __name__ == '__main__':
    __write_size__(1)

我实际上将它与Requests Streaming Uploads 一起使用,但我试图将其用作测试,看看我是否可以复制您在使用with 打开文件时获得的二进制数据流

【问题讨论】:

  • 我认为前后双下划线的名称在 Python 中是特殊的,保留用于语言本身的工作。你可能不应该那样做。继续并保留前导下划线(这使其成为私有),但丢失尾随下划线。
  • 更重要的是,您能否更具体地说明一下这段代码中什么不起作用?
  • 我怀疑这里的实际问题是 OP 对 with-statement 上下文管理器和类文件对象之间的区别感到困惑。出于所描述的目的(模拟任意大小的常量字节文件),上下文管理器是完全没有必要的。
  • 您确定您了解上下文管理器(与with 一起使用的东西)的作用吗?因为您错误地混合了generators 和上下文管理器(您没有将yield__enter__() 混合使用)。从您的问题陈述来看,您真正想要的只是一个以块的形式返回字节流的生成器。
  • @DanielPryden,我认为这是有道理的。所以我误解了我的问题。我认为通过履行with 的方法合同,我可以将其传递给Requests,但是,我应该做的是找出Requests 如何使用file 对象并实现我的生成器来提供Requests以任何方式从文件中轮询数据。

标签: python python-3.x with-statement


【解决方案1】:

记录在案

  • context manager 用于当您有一个具有初始化和清理功能的对象时。在示例中,它与文件对象一起使用。由于文件对象实现了上下文管理器协议,使用文件句柄退出 with 块将自动关闭文件。

    with open('arbitrary-{}mb.bin'.format(size), 'wb') as fd: ...

  • a generator 是一个(以编程方式)生成可迭代结果的函数。可以把它想象成一个多次返回的函数。

至于您的问题:您可以使用生成器来实现结果流,这基本上就是它们的用途:

def bytes_generator(mega_bytes):
    for i in range(mega_bytes * 1024):
        yield b'\x00'

def write_size(size):
    with open('arbitrary-{}mb.bin'.format(size), 'wb') as fd:
         for b in bytes_generator(size):
              fd.write(b)

不过,这非常低效,因为它一次只写入一个字节。但是要修复它,您只需要从生成器中修改分块。

Requests 明确允许通过生成器进行分块上传。

def gen():
    yield 'hi'
    yield 'there'

requests.post('http://some.url/chunked', data=gen())

【讨论】:

    猜你喜欢
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 2019-01-06
    • 2012-01-04
    • 2015-09-01
    • 1970-01-01
    相关资源
    最近更新 更多