从文件生成块

时间:2016-11-09 04:09:29

标签: python generator

我有一个JSON文件,想写一个函数来返回文件中接下来的10个对象的列表。我开始使用类FileProcessor和方法get_row(),它返回一个从文件中生成单个JSON对象的生成器。另一种方法get_chunk()应该返回接下来的10个对象。

这是我到目前为止所做的:

class FileProcessor(object):

    def __init__(self, filename):
        self.FILENAME = filename

    def get_row(self):
        with open( os.path.join('path/to/file', self.FILENAME), 'r') as f:
            for i in f:
                yield json.loads(i)

    def get_chunk(self):
        pass

我试过这样的话,但每次只返回前10行行。

    def get_chunk(self):
        chunk = []
        consumer = self.consume()
        for i in self.get_row():
            chunk.append(i)
        return chunk     

那么写get_chunk()的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

这是一个简单的生成器,它从另一个生成器获取值并将它们放入列表中。它应该与您的FileProcessor.get_row方法配合使用。

def count(n):
    for v in range(n):
        yield str(v)

def chunks(it, n):
    while True:
        yield [next(it) for _ in range(n)]

for u in chunks(count(100), 12):
    print(u)

<强>输出

['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']
['12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
['24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35']
['36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47']
['48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59']
['60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71']
['72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83']
['84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95']

请注意,这只会产生完整的块。如果这是一个问题,你可以这样做:

def chunks(it, n):
    while True:
        chunk = []
        for _ in range(n):
            try:
                chunk.append(next(it))
            except StopIteration: 
                yield chunk
                return
        yield chunk

将打印

['96', '97', '98', '99']

在上一次输出之后。

更好的方法是使用itertools.islice,它将处理部分最终块:

from itertools import islice

def chunks(it, n):
    while True:
        a = list(islice(it, n))
        if not a:
            return
        yield a

感谢Antti Haapala提醒我islice。 :)

答案 1 :(得分:2)

(注意:PM 2Ring打败了我!)

你的get_row方法没有返回一行 - 它会返回一个生成器,当你迭代它时会生成行。您可以在执行get_chunk的{​​{1}}方法中看到该内容。令人讨厌的是,每次调用for i in self.get_row...时,它都会再次打开文件并返回第一个对象。 get_row的问题在于您没有传递所需的行数,并且不会将get_chunk循环限制为该数字。 for获取文件中的所有行。

重新思考怎么样?你真正需要的只是一个读取行和反序列化json的生成器。 get_chunk函数已经构建完成。您可以使用python的map函数获取单行,使用next获取多行。你的课程只是对已经实现的东西的一个薄薄的包装,所以只需使用本机工具并完全跳过编写自己的类。

拳头我生成一个测试文件

itertools.islice

...

现在我可以创建一个可用于获取行或行列表的迭代器。在cpython中,您可以安全地在>>> with open('test.json', 'w') as fp: ... for obj in 'foo', 'bar', 'baz': ... fp.write(json.dumps(obj) + '\n') 函数中打开该文件,但您也可以使用map子句进行工作。

with

我可以在循环中获取所有对象

>>> json_iter = map(json.loads, open('test.json')) 
>>> next(json_iter)
'foo'
>>>
>>> with open('test.json') as fp:
>>>     json_iter = map(json.loads, open('test.json'))
>>>     next(json_iter)
'foo'

或者将其中一些列入名单

>>> for obj in map(json.loads, open('test.json')):
...     print(obj)
... 
foo
bar
baz

或合并操作

>>> list(itertools.islice(json_iter, 2))
['foo', 'bar']

关键是,简单的基于>>> json_iter = map(json.loads, open('test.json')) >>> for obj in json_iter: ... if obj == 'foo': ... list(itertools.islice(json_iter,2)) ... ['bar', 'baz'] 的迭代器可以做你想要的,而不必在每次想到新的用例时更新包装类。