Получите n строк из класса Generator в Python - PullRequest
2 голосов
/ 02 октября 2019

Я хочу печатать n строк из файла каждый раз, когда вызывается класс Generator.

Я пробовал следующее:

class FileReader:
    def __init__(self, file):
        with open(file, 'r') as fin:
            read_file = fin.read()

            # gen-comp yielding stripped lines
            lines = (line.strip() for line in read_file)
            print(lines)

Это просто возвращает все строки.

Ответы [ 4 ]

4 голосов
/ 02 октября 2019

Вы можете реализовать метод __call__, например,

import sys
from itertools import islice

class FileReader:
    def __init__(self, fname, len=3):
        self.fname = fname
        self._len = len

    def __enter__(self):
        self.fd = open(self.fname, 'r')
        return self

    def __call__(self):
        return list(islice(self.fd, self._len))

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.fd:
            self.fd.close()


with FileReader(sys.argv[1]) as f:
    print(f())
    print(f())
2 голосов
/ 02 октября 2019

Я не очень хорошо знаком с программированием классов или генераторами, но следующий набросок, который я написал, кажется, заполняет ваши критерии для печати х числа строк каждый раз, когда объект вызывается

class FileReader:
    def __init__(self, file, num_lines=10):
        fin = open(file, 'r')
        self.file_handle = fin
        self.num_lines = num_lines

    def __next__(self):
        for i in range(self.num_lines):
            yield self.file_handle.readline().strip()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.fin.close()

    def __str__(self):
        return "".join(list(next(self)))

myfile = FileReader('query4.txt', 2)
print(myfile)
print(myfile)

INPUT FILE

this is some data
this is other data
data is fun
data is weird
this is the 5th line

Поскольку вы удалили новые символы строки в своей исходной программе, я сделал то же самое, поэтому предположим, что вы хотите объединить строки X вместе. Если это не так, просто удалите .strip ()

OUTPUT

this is some datathis is other data
data is fundata is weird
0 голосов
/ 02 октября 2019

Вы говорите, что хотите генератор, и поэтому простое решение - просто написать его напрямую, используя yield. Возможно, что-то вроде этого (хотя можно улучшить структуру цикла кода):

def FileReader(filename, length):
    with open(filename, 'r') as fin:
        while True:
            group = []
            for i in range(length):
                try:
                    group.append(next(fin).strip())
                except StopIteration:
                    break
            if not group:
                break
            yield group

Это, например, будет каждый раз выводить список из 8 строк:

for g in FileReader(filename, 8):
    print(g)

Или вот альтернатива, которую я предпочитаю. Я собрал строительный блок итератора в духе itertools, который группирует любые итерируемые в списки заданной длины. Затем вы можете применить это непосредственно к объекту файла, чтобы сделать то, что вы хотите:

import itertools

def group(iterable, length):
    for key,group in itertools.groupby(
                 enumerate(iterable),
                 key=lambda elem : elem[0] // length):
        yield [elem[1] for elem in group]

Таким образом, это можно затем использовать, чтобы просто обернуть объект файла следующим образом:

fin = open(filename, "r")
for g in group(fin, 8):
    print([e.strip() for e in g])

Примечаниечто в этом случае, чтобы сохранить общность функции group, я пропустил strip и поэтому должен был сделать это в конце.

0 голосов
/ 02 октября 2019

Ваш файловый объект уже является генератором.

class FileReader:
    def __init__(self, file, lines=3):
        self.fd = open(file, 'r')
        self.lines = lines

    def __call__(self):
        for i in range(self.lines):
            print(self.fd.readline())

Это будет просто печатать пустые строки, когда вы достигнете конца файла, если это не то, что вы хотите, вы можете попробовать:

import os

class FileReader:
    def __init__(self, file, lines=3):
        self.fd = open(file, 'r')
        self.lines = lines
        self.end = self.fd.seek(0, os.SEEK_END)
        self.fd.seek(0)

    def __call__(self):
        for i in range(self.lines):
            if self.fd.tell() == self.end:
                print('Reached EOF')
                return
            print(self.fd.readline())
...