8

This code below works correct :

def file_gen(f_name):
    f = open(f_name)
    for line in f:
        yield line

gen_line = file_gen("foo.html")
gen_line.next() # '<!DOCTYPE>\n'
gen_line.next() # '<html> \n' 
gen_line.next() # ... next line in file 

But this function raises StopIteration. I don't understand why ?

def file_gen(f_name):
    f = open(f_name)
    line = f.readline()
    yield line

gen_line = file_gen('foo.html')
gen_line.next()  # '<!DOCTYPE>\n'
gen_line.next()  # StopIteration
A.M. Sultanov
  • 147
  • 2
  • 8

4 Answers4

8

You have:

def file_gen(f_name):
    f = open(f_name)
    line = f.readline()
    yield line

Notice line = f.readline() This only reads 1 line from the file.

Compare:

def g(x):
    li=range(x)
    yield li.pop()

print list(g(10))
# [9]

with this:

def g(x):
    li=range(x)
    while li:
       yield li.pop()

print list(g(10))
# [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

yield can only be called once with a particular object or expression. Once it is used by the receiver it must be regenerated. So you need a loop around reading each line of the file.

You can use your second (less readable) form this way:

def file_gen(f_name):
    f = open(f_name)
    while True:
        line = f.readline()
        if not line:
            break
        yield line

You need a loop to create the the items to yield. In your first case, for line in f: yield line is a loop.

I would rewrite your function this way:

def file_gen(f_name):
    with open(f_name) as f:
        for line in f:
            yield line
glglgl
  • 89,107
  • 13
  • 149
  • 217
dawg
  • 98,345
  • 23
  • 131
  • 206
  • 1
    @A.M.Sultanov: Because `line = f.readline()` only reads 1 line. You need to wrap that in some form of a loop -- either a `while` loop of a more readable `for` loop – dawg Nov 14 '13 at 15:40
  • 2
    Or more specifically, you only call `yield` once, so the next call to `next()` hits the end of the generator. – chepner Nov 14 '13 at 15:56
  • @chepner: Yes -- that is a better way to state it. – dawg Nov 14 '13 at 16:04
2

You get StopIteration on the second next() because you've only yielded one result. Did you mean to do this instead?

def file_gen(f_name):
    f = open(f_name)
    lines = f.readlines()
    for line in lines:
        yield line
R Hyde
  • 10,301
  • 1
  • 32
  • 28
1

doesn't

line = f.readline()

only give you one line to yield? therefore iteration stops after that...

gonkan
  • 259
  • 1
  • 7
  • but if use this form: file = open('foo.html') file.readline() file.readline() ... it doesn't stop on the second line – A.M. Sultanov Nov 14 '13 at 15:31
  • When I try that it just gives me the second line instead of the first, then stops iteration on successive next() calls, as I would expect. Anyhow, seems like you've got to the bottom of your issue... – gonkan Nov 14 '13 at 15:53
0

strong text

def text_lines(path):
   textFile = open(path, "r")
   while True:
      line = textFile.readline()
      if line :
         yield line.strip()
      else:
         break
   textFile.close()
Robox404
  • 7
  • 5