Problems with sys.stout.flush()

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat May 23 11:47:41 EDT 2009


On Sun, 24 May 2009 00:44:21 +1000, Joel Ross wrote:

> Still having the same problem if I pass it 1000 lines it will printout
> 1000 asterisks when I say lines I mean the argument <number> for the
> progress() function. I only want to printout 100 asterisks no matter how
> many lines I pass to the progress() function, that's why I need the
> printout to overwrite the last printout instead of appending to the last
> printout. 

No, you're confusing two different problems:

(1) Scale the width of the progress bar to 100 characters;

(2) Make the progress bar appear on one line instead of multiple lines.


To solve the *second* problem, use the hint already given by Carl Banks.

To solve the *first* problem, use mathematics, then re-do your method, 
because your method is wrong. Before you can write code to solve this 
problem, you first have to get the mathematics right: you want to scale 
the width of the progress bar to be 100 asterisks no matter how many 
lines you have.

(a) If you have exactly 100 lines, and you draw one asterisk per line, 
then you get a progress bar of exactly 100 asterisks.

(b) If you have 50 lines, and you want a progress bar of exactly 100 
asterisks, you need to draw *two* asterisks per line.

(c) If you have 200 lines, and you want a progress bar of exactly 100 
asterisks, you need to draw *one half* an asterisk per line (or one 
asterisk per *two* lines).

(d) If you have N lines, and you want a progress bar of exactly 100 
asterisks, each line must be equivalent to [____] asterisks.

Once you have filled in the blank, then go back to writing code.


Some further hints: I've added some commentary to your code:

def progressbar(self, number, total,  char):
    percentage = float(number*100)/total
    percentage = int(round(percentage))
    percentage = int(100 - percentage)
    # Why not combine all of the above into one line?
    # percentage = int(100 - round(number*100.0/total))

    self.f=sys.stdout
    # Why are you storing stdout as an attribute to the method? Unless 
    # you will need it again elsewhere, this is a waste.

    if percentage > 0:
        char = char * percentage
        # Carl Banks has already pointed out the problem here.

        self.f.write(char)
        self.f.flush()
        # Better written like this:
        # sys.stdout.write(char)
        # sys.stdout.flush()

        sleep(0.2)


Finally, here's a function that should do what you ask for:

from __future__ import division
import sys

def progressbar(number, total, char='*', maxwidth=100):
    done = number/total
    if not 0 <= done <= 1:
        raise ValueError('number or total out of range')
    # Scale done=1 => maxwidth chars.
    s = int(done*maxwidth)*char
    sys.stdout.write(s + '\r')
    sys.stdout.flush()
    sleep(0.2)

This should work in "normal" terminal windows (tested on Linux, should 
work on Windows and Mac too) but some IDEs may mess it up.




-- 
Steven



More information about the Python-list mailing list