Reputation:
I want to print n lines from a file everytime a Generator class is called.
I have tried the following:
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)
This simply returns all the lines.
Upvotes: 2
Views: 1459
Reputation: 3507
You say you want a generator, and so a simple solution is just to write one directly, using yield
. Something like this perhaps (though it might be possible to improve the looping structure of the code):
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
This then, for example, will print a list of 8 lines each time:
for g in FileReader(filename, 8):
print(g)
Or here's an alternative that I prefer. I've knocked up an iterator building block, in the spirit of itertools
, which groups up any Iterable into lists of a specified length. You can then apply this directly to a file object to do what you want:
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]
So this can then be used to just wrap the file object like this:
fin = open(filename, "r")
for g in group(fin, 8):
print([e.strip() for e in g])
Note that in this case, to preserve the generality of the group
function, I've omitted the strip
and therefore had to do it at the end.
Upvotes: 1
Reputation: 1747
Your file object is already a generator.
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())
This will just print empty lines when you reach the end of the file, if that's not what you want then you can try:
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())
Upvotes: 0
Reputation: 6600
You could implement a __call__
method like,
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())
Upvotes: 3
Reputation: 12190
I am not that familiar with class programing or generators but the following i drafted seems to fill your criteria to print x number of lines each time the object is called
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
As you have stripped new line chars in your original program i have done the same so assume you want to concat the X lines together. If thats not the case then just remove the .strip()
OUTPUT
this is some datathis is other data
data is fundata is weird
Upvotes: 1