堆叠文件对象周围的过滤器

时间:2016-01-30 23:15:33

标签: python file filter io

我想在open()函数周围堆叠过滤器。例如,假设这些过滤器将从文件中读取的流中的每个遇到的a个字符更改为b

例如,这是一个代码示例:

def filter (stream):
    for line in stream:
        yield line.replace('a', 'b')

def add_filter(filter, file):
    return io.TextIOWrapper(filter(file))

def processing_file(f):
    import sys
    for line in f:
        sys.stdout.write("aa: " + line)

f = open('./example.txt', 'r')
f = add_filter(filter, f)
processing_file(f) 

我想filter_a()函数应返回TextIOWrapper来模仿open()函数的结果。但是,我一直有以下错误消息:

AttributeError: 'generator' object has no attribute 'readable'

事实上,我理解错误,但我不知道如何解决并使其正常工作。

2 个答案:

答案 0 :(得分:3)

您可以直接在过滤器生成器上进行迭代:

with open('./example.txt', 'r') as f:
    for line in filter(f):
        sys.stdout.write("aa: " + line)

答案 1 :(得分:1)

我找到了解决自己问题的方法......首先,我必须承认我的问题并不完全正确,可能缺乏精确性。所以,我不怪任何人放弃它。

我的初衷是在流(open())上提供可堆叠的过滤器框架。试图让它易于使用,也是。

我主要在StackOverflow上的这个answer中找到灵感,它解决了我约90%的问题。

因此,假设我们有两个过滤器(编码为生成器):

def tab_filter(stream):
    for line in stream:
        yield line.replace ('\t', ' ' * 8)

def a_filter(stream):
    for line in stream:
        yield line.replace ('a', 'z')

然后,我们有这个类允许将一个生成器包装在一个流中:

class IterStream(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)
        try:
            while count < size:
                chunk = self.next()
                data += chunk
                count += len(chunk)
        except StopIteration:
            self.leftover = ''
            return data

        if count > size:
            self.leftover = data[size:]

        return data[:size]

在代码中使用它将如下:

import sys
f = IterStream(a_filter(IterStream(tab_filter(open('Example.txt', 'r')))))
for line in f:
    sys.stdout.write("aa: " + line)

但是,这还不完全令人满意,因为我们需要大量无用的功能堆叠。所以,我决定将它包装在装饰器中:

def streamfilter(filter):
    def stream(iostream):
        return IterStream(filter(iostream))
    return stream

@streamfilter
def tab_filter(stream):
    for line in stream:
        yield line.replace ('\t', ' ' * 8)

@streamfilter
def a_filter(stream):
    for line in stream:
        yield line.replace ('a', 'z')

然后,现在使用代码要容易得多:

import sys
f = a_filter(tab_filter(open('Example.txt', 'r')))
for line in f:
    sys.stdout.write("aa: " + line)

我希望你们中的一些人会发现这几行很有用。

相关问题