Adapt an iterator to behave like a file-like object in Python

前端 未结 8 1133
Happy的楠姐
Happy的楠姐 2020-12-13 07:00

I have a generator producing a list of strings. Is there a utility/adapter in Python that could make it look like a file?

For example,

>>> d         


        
相关标签:
8条回答
  • 2020-12-13 07:21

    Here's a solution that should read from your iterator in chunks.

    class some_magic_adaptor:
      def __init__( self, it ):
        self.it = it
        self.next_chunk = ""
      def growChunk( self ):
        self.next_chunk = self.next_chunk + self.it.next()
      def read( self, n ):
        if self.next_chunk == None:
          return None
        try:
          while len(self.next_chunk)<n:
            self.growChunk()
          rv = self.next_chunk[:n]
          self.next_chunk = self.next_chunk[n:]
          return rv
        except StopIteration:
          rv = self.next_chunk
          self.next_chunk = None
          return rv
    
    
    def str_fn():
      for c in 'a', 'b', 'c':
        yield c * 3
    
    ff = some_magic_adaptor( str_fn() )
    
    while True:
      data = ff.read(4)
      if not data:
        break
      print data
    
    0 讨论(0)
  • 2020-12-13 07:31

    There is one called werkzeug.contrib.iterio.IterIO but note that it stores the entire iterator in its memory (up to the point you have read it as a file) so it might not be suitable.

    http://werkzeug.pocoo.org/docs/contrib/iterio/

    Source: https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/contrib/iterio.py

    An open bug on readline/iter: https://github.com/mitsuhiko/werkzeug/pull/500

    0 讨论(0)
  • 2020-12-13 07:34

    this is exactly what stringIO is for ..

    >>> import StringIO
    >>> some_var = StringIO.StringIO("Hello World!")
    >>> some_var.read(4)
    'Hell'
    >>> some_var.read(4)
    'o Wo'
    >>> some_var.read(4)
    'rld!'
    >>>
    

    Or if you wanna do what it sounds like

    Class MyString(StringIO.StringIO):
         def __init__(self,*args):
             StringIO.StringIO.__init__(self,"".join(args))
    

    then you can simply

    xx = MyString(*list_of_strings)
    
    0 讨论(0)
  • 2020-12-13 07:38

    First of all, your generator will have to yield byte objects. While there isn't anything built-in, you can use a combination of http://docs.python.org/library/stringio.html and itertools.chain.

    0 讨论(0)
  • 2020-12-13 07:40

    The problem with StringIO is that you have to load everything into the buffer up front. This can be a problem if the generator is infinite :)

    from itertools import chain, islice
    class some_magic_adaptor(object):
        def __init__(self, src):
            self.src = chain.from_iterable(src)
        def read(self, n):
            return "".join(islice(self.src, None, n))
    
    0 讨论(0)
  • 2020-12-13 07:41

    Here's a modified version of John and Matt's answer that can read a list/generator of strings and output bytearrays

    import itertools as it
    from io import TextIOBase
    
    class IterStringIO(TextIOBase):
        def __init__(self, iterable=None):
            iterable = iterable or []
            self.iter = it.chain.from_iterable(iterable)
    
        def not_newline(self, s):
            return s not in {'\n', '\r', '\r\n'}
    
        def write(self, iterable):
            to_chain = it.chain.from_iterable(iterable)
            self.iter = it.chain.from_iterable([self.iter, to_chain])
    
        def read(self, n=None):
            return bytearray(it.islice(self.iter, None, n))
    
        def readline(self, n=None):
            to_read = it.takewhile(self.not_newline, self.iter)
            return bytearray(it.islice(to_read, None, n))
    

    usage:

    ff = IterStringIO(c * 3 for c in ['a', 'b', 'c'])
    
    while True:
        data = ff.read(4)
    
        if not data:
            break
    
        print data
    
    aaab
    bbcc
    c
    

    alternate usage:

    ff = IterStringIO()
    ff.write('ffffd')
    ff.write(c * 3 for c in ['a', 'b', 'c'])
    
    while True:
        data = ff.read(4)
    
        if not data:
            break
    
        print data
    
    ffffda
    aabb
    bccc
    
    0 讨论(0)
提交回复
热议问题