python 的打印输出本质上是先将内容存入缓冲区,然后在接收到触发机制后才会将缓冲区的内容输出到控制台。本篇介绍 print 函数,了解它的本质,将有助于掌握 python 中信息流的转换与输出。

sys.stdout.write

print 函数的底层是调用 sys.stdout.write 函数。关于 sys.stdout.write 函数,官网信息如下:

1
2
3
4
5
6
7
Docstring:
Write to current stream after encoding if necessary

Returns
-------
len : int
number of items from input parameter written to stream.

解释为将内容(必须是字符串)写入到信息流中,其实是写入到缓冲区中。当我们想要将缓冲区里的内容打印输出到控制台时,需要使用函数 sys.stdout.flush,即触发发送机制。

1
2
3
4
5
Signature: sys.stdout.flush()
Docstring:
trigger actual zmq send

send will happen in the background thread

print

print 函数的官网信息如下:

1
2
3
4
5
6
7
8
9
10
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type: builtin_function_or_method

解释为将内容(可以为非字符串,如整数)输出到信息流或者 sys.stdout 中。即内容可以写入文件对象中,请参考我的另一篇:把 Python 的 print 函数输出到文件。默认是写入到 sys.stdout,即标准输出。当缓存区的内容受到触发机制时,将直接将执行 sys.stdout 的线程的内容输出到控制台。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Type:           OutStream
String form: <ipykernel.iostream.OutStream object at 0x7efdb86b3c40>
File: /usr/local/miniconda/lib/python3.9/site-packages/ipykernel/iostream.py
Docstring:
A file like object that publishes the stream to a 0MQ PUB socket.

Output is handed off to an IO Thread
Init docstring:
Parameters
----------
name : str {'stderr', 'stdout'}
the name of the standard stream to replace
watchfd : bool (default, True)
Watch the file descripttor corresponding to the replaced stream.
This is useful if you know some underlying code will write directly
the file descriptor by its number. It will spawn a watching thread,
that will swap the give file descriptor for a pipe, read from the
pipe, and insert this into the current Stream.
isatty : bool (default, False)
Indication of whether this stream has termimal capabilities (e.g. can handle colors)

常见的触发机制有:

  1. end = '\n',即遇到换行符,则输出到控制台;
  2. flush = True,即 sys.stdout.flush 触发发送缓冲区内容到控制台机制;
  3. 显示调用 sys.stdout.flush
  4. 程序结束。

值得一提的是,print 函数是对 sys.stdout.write 函数的高层封装,具有更强大的功能,不仅能够直接打印非字符串数据,还能够打印多个数据段,并以 sep 指定的字符分割,默认以空格分割,即 sep=' '.

例子

编写程序,内容如下,保存为 test.py,在终端中用如下命令运行:

1
python test.py

直接打印到控制台。下面代码会 1 秒中打印一个字符到控制台。

1
2
3
4
5
6
import sys
import time

for i in range(3):
print(i)
time.sleep(1)

程序结束触发打印到控制台。下面代码会等 3 秒后一次性打印所有字符到控制台,即缓冲区的内容等 3 秒后接到触发机制才打印。

1
2
3
4
5
6
import sys
import time

for i in range(3):
print(i, end=" ", flush=False)
time.sleep(1)
1
2
3
4
5
6
import sys
import time

for i in range(3):
sys.stdout.write(str(i))
time.sleep(1)

使用 flush=True 触发打印到控制台。下面代码会 1 秒中打印一个字符到控制台。

1
2
3
4
5
6
import sys
import time

for i in range(3):
print(i, end=" ", flush=True)
time.sleep(1)

使用 end="\n" 触发打印到控制台。下面代码会 1 秒中打印一个字符到控制台。

1
2
3
4
5
6
import sys
import time

for i in range(3):
print(i, end="\n", flush=False)
time.sleep(1)

使用 sys.stdout.flush 触发打印到控制台。下面代码会 1 秒中打印一个字符到控制台。

1
2
3
4
5
6
7
import sys
import time

for i in range(3):
print(i, end=" ", flush=False)
sys.stdout.flush()
time.sleep(1)

参考文献

  1. sys.stdout.flush的作用
  2. Python中print()本质与sys.stdout.write()区别