本文记录一些与python输入输出有关的事情。主要分为以下几个部分标准输入
标准输出
用print输出进度条
StringIO
标准输入
总结一下sys.stdin的几种用法。
注:下面这些代码的功能类似input,代码写在py文件里,用cmd调用运行时,需要输入一些字符串,如果输入多行字符串要用Ctrl+D(Unix)或Ctrl+Z(Windows)停止输入,然后字符串的内容就会赋值给变量a,程序再对a进行后续处理。
1.输入多行,a是一个多行字符串
import sys
a = sys.stdin.read()
print(a)
2.输入多行,a是一个列表,列表中每一个元素对应字符串的一行,行末的\n也还在
import sys
a = sys.stdin.readlines()
print(a)
可以这样用
import sys
for line in sys.stdin.readlines():
print(line.strip())
3.输入单行,a直接就是那一行字符串
import sys
a = sys.stdin.readline()
print(a)
4.每调用一次next要多输入一行
import sys
f = sys.stdin
a = next(f)
b = next(f)
print(a, b)
循环则需要不停输入
import sys
for line in sys.stdin:
print(line)
用readline可以达到相同效果
import sys
while True:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print(line)
注意以下几点上面这些无法在jupyter中尝试,要写入文件,运行这个文件,python main.py
每一行都是raw格式的,即输入ab\nc时得到的字符串是r'ab\nc',实际上是'ab\\nc',因此print出来后\n还在;而输入多行时回车则不一样,比如输入ab\nc回车,得到的是'ab\\nc\n'
sys.stdin与可读文件对象具有相同的类型,如下所示,因此才都可以调用read,readlines等方法。只是stdin默认从运行py文件的窗口中读取字符,而open(file, 'r')则从file文件中读取字符。
import sys
print(sys.stdin)
with open('test.txt', 'r') as f:
print(f)
# 输出结果
<_io.TextIOWrapper name='' mode='r' encoding='cp936'>
<_io.TextIOWrapper name='test.txt' mode='r' encoding='cp936'>
我们也可以写着标准输入的代码,实际上却将文件内容传进来,比如两个文件分别像下面这样编辑(放在相同目录下)
# main.py
import sys
for line in sys.stdin.readlines():
print(line.strip())
# test.txt
abc
bcd
efg
(linux下)运行python main.py < test.txt,则会将test.txt文件中的内容输出。这样做和直接运行下面的代码是一样的
with open('test.txt', 'r') as f:
for line in f.readlines():
print(line.strip())
另外,python3中input可以接受一行的输入,与readline的区别在于input可以给出一段提示,而且input会把最后的\n去掉
a = input('please input one line:')
print(a)
标准输出
sys.stdout与可写文件对象具有相同的类型,如open(file, 'w')这个对象,它们都可以通过write方法将字符串输出到目标位置open(file, 'w').write()将字符串写入file文件,
stdout.write()将字符串写到运行py文件的窗口,功能和我们熟悉的print相同。而实际上print正是调用stdout.write()实现的。print是stdout.write的扩展,比如后者只能接受字符串,而前者可以接受很多类型;还有print默认最后加一个\n、可以接受多个参数等等。
因此当我们看到这样的代码,看成print就好了
import sys
sys.stdout.write('abc')
有时我们会看到这种形式
import sys
sys.stdout.write('abc')
sys.stdout.flush()
flush只是为了实时显示输出(将原来写到缓存区中的内容显示出来),比如下面这段代码,不加flush时5个数字会在最后一起输出,而用flush则会一个一个显示出来
import sys
import time
for i in range(5):
sys.stdout.write(str(i))
# sys.stdout.flush()
time.sleep(0.5)
其实最后加一个\n不需要flush也会实时输出
import sys
import time
for i in range(5):
sys.stdout.write('{}\n'.format(i))
time.sleep(0.5)
我们一般用print都会实时输出,因为它默认最后输出一个\n,如果最后去掉\n,则也不会实时输出,如下所示
import time
import sys
for i in range(5):
print(i, end='')
# sys.stdout.flush()
time.sleep(0.5)
我们可以加上flush那一行使其实时输出,也可以改flush参数print(i, end='', flush=True)。
前面提到,print()是在调用sys.stdout.write(),那么如果将sys.stdout换成文件(反正类型是相同的),是不是print就可以输出到文件了呢?确实如此。试一试下面一段代码
import sys
sys.stdout = open('test.txt', 'w')
print('first line')
print('second line')
运行后test.txt文件就变成了
first line
second line
其实这也可以用print的参数来完成
with open('test.txt', 'w') as f:
print('first line', file=f)
print('second line', file=f)
回过头来发现,我们把print的参数玩了一个遍
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
此外,与输入相同,输出时也可以用print不加改动,将输出重定向到文件中
print('first line')
print('second line')
上面代码在linux下用python main.py >> test.txt运行,即可将print写入test.txt文件中。
显示进度
我们这里不用python中的一些库来实现进度条,而是用print来完成。使用\r每次将光标移动到行首,如下所示
import time
n = 142
for i in range(n):
print('\r{}/{}'.format(i+1, n), end='')
time.sleep(0.05)
用print('{} / {}'.format(i+1, n), end='\r')一般也可以。
但有时基数太大,比如1545643/55969685,很难很快看出进行到哪了,这时需要看百分比
import time
n = 142
for i in range(n):
print('\r{0:.0%}'.format((i+1)/n), end='')
time.sleep(0.05)
也可以既显示实际数量,又显示进度条
import time
n = 206
for i in range(n):
m = int((i+1) / n * 60)
progressbar = '\r{}/{}, |{}>{}|'.format(i+1, n, '='*m, '-'*(60-m))
print(progressbar, end='')
time.sleep(0.05)
显示结果如下
116 / 206, |=================================>---------------------------|
上面如果运行很大基数的情况,可能会出问题,看下面这个例子,为了更快出结果,我将time.sleep省掉了
n = 5000
for i in range(n):
count = i + 1
print('{}/{}'.format(count, n), end='\r')
输出结果没有全都在一行,而是这样的,n越大会积累越多行。
2550 / 5000
4672 / 5000
5000 / 5000
这个问题应该跟flush有关,调用\r虽然也会实时显示,但缓存区中的东西貌似没有清理,积累到一定程度就会输出个\n来flush,如果我们加一个flush=True就可以解决这个问题
n = 5000
for i in range(n):
count = i + 1
print('{}/{}'.format(count, n), end='\r', flush=True)
但这样做屏幕就会极频繁地刷新,本来早该结束的程序却因为没有输出完而没有停止,后面程序运行的结果也没法输出。所以可以少输出一些
n = 5000
for i in range(n):
count = i + 1
if count % 50 == 0:
print('{}/{}'.format(count, n), end='\r', flush=True)
StringIO
在内存中读写字符串。想象一个场景:一个函数需要输入的参数是文件对象,但我们现在手上只有字符串,如果想传入这个函数中,就要先读入一个文件,再读出来传入,然后还要把文件删掉,这就非常麻烦。StringIO可以让我们直接从内存中读取字符串形成一个文件对象
from io import StringIO
f = StringIO('Hello World!')
f.read()
f也可以调用write继续写入。StringIO只能读取字符串,如果是二进制数据,要用BytesIO。
注意事项想打空行用print(),不要用print('\n'),因为后者会打两个空行,相当于print('\n', end='\n')
更多遇到了再补充…
专栏信息
专栏目录:目录