Skip to content

Commit 555733f

Browse files
martin-martiniansedanojima80525
committed
Add materials
Co-authored-by: Ian <[email protected]> Co-authored-by: Jim Anderson <[email protected]>
1 parent c115d9c commit 555733f

12 files changed

+155
-0
lines changed

flush-print/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# How to Flush the Output of the Python Print Function
2+
3+
This directory contains code associated with the Real Python tutorial [How to Flush the Output of the Python Print Function](https://realpython.com/python-flush-print-output/).
4+
5+
## Installation
6+
7+
You don't need to install anything apart from a Python interpreter >=3.6 to run the example files.
8+
9+
## Countdown Script Variations
10+
11+
You can find all the code snippets that you've seen in the tutorial. For convenience, they're provided as separate files that all start with `countdown` and describe their differences with the rest of the file name. You can run each of the files separately without needing to edit the code, to see all the examples shown in the tutorial. Please visit the tutorial link for additional context.
12+
13+
## Terminal Based Visual Progress Indicators
14+
15+
Additionally, this directory also contains two scripts that show example implementations of terminal animations that you can build using `print()` and its parameters:
16+
17+
- [`spinner.py`](spinner.py)
18+
- [`progress.py`](progress.py)
19+
20+
Both of them utilize explicit flushing and you can learn more about how to build them in [Your Guide to the Python `print()` Function](https://realpython.com/python-print/).
21+
22+
## Buffer Size Approximations
23+
24+
Finally, if you're curious to dive somewhat deeper into the rabbit hole of buffering in Python, you can take a look at [`buffersize.py`](buffersize.py).
25+
26+
There doesn't seem to be a way to get the size of the default buffer for stdout on your operating system directly through a Python object. If you know or find a way, please [contact the author](#about-the-author), I'd be very curious to know :)
27+
28+
This script gives you a way to approximate the buffer size that Python uses when writing to stdout on your operating system and configuration. Note that this can be quite different between different setups.
29+
30+
The approach to calculate it is somewhat manual:
31+
32+
1. Run the script
33+
1. Note if the numbers that it prints pause in between before the script finishes execution
34+
- If they pause, remember the last number that got printed before the pause
35+
- If they don't pause, increase the value of `SLIGHTLY_TOO_LARGE_FOR_BUFFER` by `10_000` and start from the top
36+
37+
Continue doing this until your script paused when printing the numbers, and you noted the number that displayed last during the pause. Once you have that number, subtract it from the value that `SLIGHTLY_TOO_LARGE_FOR_BUFFER` currently has to calculate your buffer size estimation, for example:
38+
39+
```python
40+
SLIGHTLY_TOO_LARGE_FOR_BUFFER = 80_000
41+
42+
# Script paused at 10919
43+
44+
bufsize = 80_000 - 10919
45+
print(bufsize) # 69081 <-- Your buffer size approximation
46+
```
47+
48+
You can divide the number you get by `1000` to get an estimation of your buffer size for stdout in Kilobytes. In the example above, on a macOS system with a M1 chip, the buffer size of stdout when interacting with it through Python's `print()` would therefore be approximately 69 Kilobytes.
49+
50+
If you want to, you could even drill down further with some manual binary search to find the exact byte when the break first occurs.
51+
52+
The idea of this script is that each of these printed numbers take up exactly 6 bytes in the buffer, which you assure with the format specifier in the f-string that you pass to `print()`. When the buffer gets filled up so much that it needs to flush during the execution of your script, then you run into the break in the printout, caused by the call to `time.sleep()` executing. Finally, when the script finishes execution after the break, Python flushes the rest of the buffer contents, which prints the remaining numbers to your terminal.
53+
54+
Finally, you need to subtract from the current value of `SLIGHTLY_TOO_LARGE_FOR_BUFFER` because we assume that the buffer flushes continuously when it gets full, which means that whatever is in the buffer when the script is done should represent a full buffer.
55+
56+
If you have better and more precise ways to calculate the buffer size, or have spotted a logical or computational mistake in these calculations, then please let us know!
57+
58+
## About the Author
59+
60+
Martin Breuss - Email: [email protected]
61+
62+
## License
63+
64+
Distributed under the MIT license. See `LICENSE` in the root directory of this `materials` repo for more information.

flush-print/buffersize.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sys
2+
import time
3+
4+
# Experiment with changing this number to hone in on the buffer size
5+
# on your operating system
6+
SLIGHTLY_TOO_LARGE_FOR_BUFFER = 10_000
7+
8+
for x in range(SLIGHTLY_TOO_LARGE_FOR_BUFFER // 6):
9+
sys.stdout.write(f"{x:6}")
10+
11+
time.sleep(2)

flush-print/countdown.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from time import sleep
2+
3+
for i in range(3, 0, -1):
4+
print(i)
5+
sleep(1)
6+
print("Go!")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from time import sleep
2+
3+
for second in range(3, 0, -1):
4+
print(f"{second}\n", end="")
5+
sleep(1)
6+
print("Go!")

flush-print/countdown_flush.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from time import sleep
2+
3+
for second in range(3, 0, -1):
4+
print(second, flush=True)
5+
sleep(1)
6+
print("Go!")

flush-print/countdown_line.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from time import sleep
2+
3+
for second in range(3, 0, -1):
4+
print(second, end=" ")
5+
sleep(1)
6+
print("Go!")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from time import sleep
2+
3+
for second in range(3, 0, -1):
4+
print(second, end=" ", flush=True)
5+
sleep(1)
6+
print("Go!")

flush-print/countdown_partial.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import functools
2+
from time import sleep
3+
4+
unbuffered_print = functools.partial(print, flush=True)
5+
6+
for second in range(3, 0, -1):
7+
unbuffered_print(second)
8+
sleep(1)
9+
print("Go!")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from time import sleep
2+
3+
for second in range(3, 0, -1):
4+
print(second, "", sep="\n", end="")
5+
sleep(1)
6+
print("Go!")

flush-print/countdown_stderr.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import sys
2+
from time import sleep
3+
4+
for i in range(3, 0, -1):
5+
print(i, end=" ", flush=True)
6+
print(f"[State: '{i}']", file=sys.stderr, end=" ")
7+
sleep(1)
8+
print("Go!")

0 commit comments

Comments
 (0)