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

前端 未结 8 1138
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条回答
  •  Happy的楠姐
    2020-12-13 07:43

    The "correct" way to do this is inherit from a standard Python io abstract base class. However it doesn't appear that Python allows you to provide a raw text class, and wrap this with a buffered reader of any kind.

    The best class to inherit from is TextIOBase. Here's such an implementation, handling readline, and read while being mindful of performance. (gist)

    import io
    
    class StringIteratorIO(io.TextIOBase):
    
        def __init__(self, iter):
            self._iter = iter
            self._left = ''
    
        def readable(self):
            return True
    
        def _read1(self, n=None):
            while not self._left:
                try:
                    self._left = next(self._iter)
                except StopIteration:
                    break
            ret = self._left[:n]
            self._left = self._left[len(ret):]
            return ret
    
        def read(self, n=None):
            l = []
            if n is None or n < 0:
                while True:
                    m = self._read1()
                    if not m:
                        break
                    l.append(m)
            else:
                while n > 0:
                    m = self._read1(n)
                    if not m:
                        break
                    n -= len(m)
                    l.append(m)
            return ''.join(l)
    
        def readline(self):
            l = []
            while True:
                i = self._left.find('\n')
                if i == -1:
                    l.append(self._left)
                    try:
                        self._left = next(self._iter)
                    except StopIteration:
                        self._left = ''
                        break
                else:
                    l.append(self._left[:i+1])
                    self._left = self._left[i+1:]
                    break
            return ''.join(l)
    

提交回复
热议问题