Since print issues a newline, and you cannot go back after that, you have to prevent at all costs that a newline char to be issued in the terminal.
You can do it by redirecting sys.stdout. print will output to your new stream. In your stream, remove the linefeed and add a carriage return. Done
import sys
def f(x):
    for i in range(x):
        print i
class fake():
    def __init__(self):
        self.__out = sys.stdout
    def write(self,x):
        r = self.__out.write(x.replace("\n","")+"\r")
        self.__out.flush()  # flush like if we wrote a newline
        return r
sys.stdout=fake()
f(5)
Result:
- on a terminal (windows or Linux): only 4 is shown
- redirecting to a file: we see all numbers separated by \rchars
Ok it's a hack but we cannot modify f and we did not... Mission accomplished.
It may be useful to restore sys.stdout to its original value once we're done.