Skip to content Skip to sidebar Skip to footer

Why While Loop Is Sticking At Raw_input? (python)

In the following code i am trying to make a 'more' command (unix) using python script by reading the file into a list and printing 10 lines at a time and then asking user do you wa

Solution 1:

You're constructing your slices wrong: The second parameter in a slice gives the stop position, not the chunk size:

chunk = 10
start = 0
stop = chunk
end = len(lines)
while True:
    block = lines[start:stop]     # use stop, not chunk!
    for i in block:
        print i
    if raw_input('Print More..') notin ['y', 'Y'] or stop >= end:
        break
    start += chunk
    stop += chunk

Solution 2:

Instead of explaining why your code doesn't work and how to fix it (because Tim Pietzcker already did an admirable job of that), I'm going to explain how to write code so that issues like this don't come up in the first place.

Trying to write your own explicit loops, checks, and index variables is difficult and error-prone. That's why Python gives you nice tools that almost always make it unnecessary to do so. And that's why you're using Python instead of C.

For example, look at the following version of your program:

count = 10withopen('/Users/abc/testfile.txt', 'r') as testfile:
    for i, line inenumerate(testfile):
        print line
        if (i + 1) % count == 0:
            if raw_input('Print More..') notin ['y', 'Y']:
                break

This is shorter than the original code, and it's also much more efficient (no need to read the whole file in and then build a huge list in advance), but those aren't very good reasons to use it.

One good reason is that it's much more robust. There's very little explicit loop logic here to get wrong. You don't even need to remember how slices work (sure, it's easy to learn that they're [start:stop] rather than [start:length]… but if you program in another language much more frequently than Python, and you're always writing s.sub(start, length), you're going to forget…). It also automatically takes care of ending when you get to the end of the file instead of continuing forever, closing the file for you (even on exceptions, which is painful to get right manually), and other stuff that you haven't written yet.

The other good reason is that it's much easier to read, because, as much as possible, the code tells you what it's doing, rather than the details of how it's doing it.

But it's still not perfect, because there's still one thing you could easily get wrong: that (i + 1) % count == 0 bit. In fact, I got it wrong in my first attempt (I forgot the +1, so it gave me a "More" prompt after lines 0, 10, 20, … instead of 9, 19, 29, …). If you have a grouper function, you can rewrite it even more simply and robustly:

withopen('/Users/abc/testfile.txt', 'r') as testfile:
    for group in grouper(testfile, 10):
        for line in group:
            print line
        if raw_input('Print More..') notin ['y', 'Y']:
            break

Or, even better:

withopen('/Users/abc/testfile.txt', 'r') as testfile:
    for group in grouper(testfile, 10):
        print'\n'.join(group)
        if raw_input('Print More..') notin ['y', 'Y']:
            break

Unfortunately, there's no such grouper function built into, say, the itertools module, but you can write one very easily:

def grouper(iterator, size):
    return itertools.izip(*[iterator]*size)

(If efficiency matters, search around this site—there are a few questions where people do in-depth comparisons of different ways to achieve the same effect. But usually it doesn't matter. For that matter, if you want to understand why this groups things, search this site, because it's been explained at least twice.)

Solution 3:

As @Tim Pietzcker pointed out, there's no need of updating chunk here, just use start+10 instead of chunk.

block = lines[start:start+10]

and update start using start += 10.

Another alternative solution using itertools.islice():

withopen("data1.txt") as f:
    slc=islice(f,5)            #replace 5 by 10 in your casefor x in slc:
        print x.strip()
    while raw_input("wanna see more : ") in("y","Y"):     
        slc=islice(f,5)        #replace 5 by 10 in your casefor x in slc:
            print x.strip()

this outputs:

12345wanna see more :y678910wanna see more :n

Post a Comment for "Why While Loop Is Sticking At Raw_input? (python)"