题 你如何从Python中读取stdin?


我正在尝试做一些 代码高尔夫 挑战,但他们都需要输入 stdin。我如何在Python中获得它?


1174
2017-09-20 05:48


起源




答案:


你可以使用 fileinput 模块:

import fileinput

for line in fileinput.input():
    pass

fileinput 将循环遍历指定为命令行参数中指定的文件名的输入中的所有行,如果未提供参数则循环标准输入。


804
2017-09-20 05:53





有几种方法可以做到这一点。

  • sys.stdin 是一个类似文件的对象,您可以在其上调用函数 read 要么 readlines 如果你想阅读所有内容,或者你想阅读所有内容并自动将其拆分为换行符。 (你需要 import sys 为了这个工作。)

  • 如果你想 提示 用户输入,即可使用 raw_input 在Python 2.X中,只是 input 在Python 3中。

  • 如果您实际上只是想阅读命令行选项,可以通过以下方式访问它们 sys.argv中 名单。

你可能会发现 这篇关于Python中I / O的Wikibook文章 也是一个有用的参考。


585
2017-07-20 10:30





import sys

for line in sys.stdin:
    print line

333
2018-03-03 19:05



这是正确的答案。 - thepure12
请注意,这将在末尾包含换行符 - brittohalloran
要在最后删除换行符,请使用 line.rstrip() - brittohalloran
我同意。这是正确的答案。 - Teekin


Python还具有内置函数 input() 和 raw_input()。请参阅下面的Python文档 内置功能

例如,

name = raw_input("Enter your name: ")   # Python 2.x

要么

name = input("Enter your name: ")   # Python 3

180
2017-09-30 09:08



这读取了一行,这不是OP所要求的。我将这个问题解释为“如何从打开的文件句柄中读取一堆行直到EOF?” - tripleee
OP不要求从键盘读取输入,他要求从标准输入读取,在比赛情况下通常会向参赛者提供。 - chrisfs


这是来自 学习Python

import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."

在Unix上,您可以通过执行以下操作来测试它:

% cat countlines.py | python countlines.py 
Counted 3 lines.

在Windows或DOS上,您可以:

C:\> type countlines.py | python countlines.py 
Counted 3 lines.

160
2017-07-30 04:10



这是在Python中计算行数的更高内存效率(也许更快)的方法: print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), '')))。 看到 wc-l.py - jfs
指某东西的用途 cat 这是多余的。对Unix系统的正确调用是 python countlines.py < countlines.py。 - istepaniuk
“学习Python”在指导用户使用方面是错误的 readlines()。文件对象旨在迭代而不实现内存中的所有数据。 - Aaron Hall♦


其他人提出的答案:

for line in sys.stdin:
  print line

非常简单和pythonic,但必须注意脚本将等到EOF开始迭代输入行。

这意味着 tail -f error_log | myscript.py 不会按预期处理行。

这种用例的正确脚本是:

while 1:
    try:
        line = sys.stdin.readline()
    except KeyboardInterrupt:
        break

    if not line:
        break

    print line

UPDATE
从评论中已经清除,在python 2上只有可能涉及缓冲,因此在发出打印调用之前,您最终会等待缓冲区填充或EOF。


85
2017-08-09 16:31



该 for line in sys.stdin: 模式 才不是 等待EOF。但是如果你测试非常小的文件,响应可能会被缓冲。测试更多数据,看它是否读取中间结果。 - mb.
我在等待文件结束或缓冲时,在使用python 2.6.6时从流中获取输入,但是在3.1.3中我没有。注意 print line 不会在3.1.3中醒来,但是 print(line) 确实。 - ctrl-alt-delor
我的python 2.7.5“for sys.stdin中的行”,阻塞直到EOF或一些合理数量的数据已缓冲。适用于流处理。对于逐行处理或用户输入不适用。 - Sean
我怀疑这与libc中tty的检测有关,所以当你管道它检测到交互式shell时它检测到没有tty,来自expect-dev的unbuffer是一个方便的工具我相信通过ld_preload注入一个shim所以is_atty返回true(I怀疑它是如何处理的) - Mâtt Frëëman
@Sean: 错误。 for line in sys.stdin: 不会“阻止EOF”。有一个 Python 2中的预读错误 延迟线直到相应的缓冲区已满。这是一个与EOF无关的缓冲问题。要解决方法,请使用 for line in iter(sys.stdin.readline, ''): (使用 io.open() 对于普通文件)。你在Python 3中不需要它。 - jfs


你如何从Python中读取stdin?

我正在尝试做一些代码高尔夫挑战,但它们都需要输入来自stdin。我如何在Python中获得它?

您可以使用:

  • sys.stdin  - 类似文件的对象 - 调用 sys.stdin.read() 阅读一切。
  • input(prompt)  - 传递一个可选的提示输出,它从stdin读取到第一个换行符,它会被删除。您必须反复执行此操作才能获得更多行,在输入结束时它会引发EOFError。 (可能不适合打高尔夫球。)在Python 2中,这是 rawinput(prompt)
  • open(0).read()  - 在Python 3中 open 接受 文件描述符 (表示操作系统IO资源的整数),0是描述符 stdin。它返回一个类似文件的对象 sys.stdin  - 可能是打高尔夫球的最佳选择。
  • open('/dev/stdin').read() - 如同 open(0)适用于Python 2和3,但不适用于Windows(甚至Cygwin)。
  • fileinput.input()  - 在中列出的所有文件中的行上返回迭代器 sys.argv[1:],或者stdin,如果没有给出。使用像 ''.join(fileinput.input())

sys 和 fileinput 当然必须分别进口。

sys.stdin 与Python 2和3,Windows,Unix兼容的示例

你只需要 read 从 sys.stdin例如,如果将数据传递给stdin:

$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo

文件示例

假设你有一个文件, inputs.txt,我们可以接受该文件并将其写回:

python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt

更长的答案

这是一个完整的,易于复制的演示,使用两种方法,内置函数, input (使用 raw_input 在Python 2),和 sys.stdin。数据未经修改,因此处理是非操作。

首先,让我们为输入创建一个文件:

$ python -c "print('foo\nbar\nbaz')" > inputs.txt

使用我们已经看到的代码,我们可以检查我们是否已经创建了该文件:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt 
foo
bar
baz

这是帮助 sys.stdin.read 来自Python 3:

read(size=-1, /) method of _io.TextIOWrapper instance
    Read at most n characters from stream.

    Read from underlying buffer until we have n characters or we hit EOF.
    If n is negative or omitted, read until EOF.

内置功能, input (raw_input 在Python 2)

内置功能 input 从标准输入读取到换行符的换行符(补充 print,默认情况下会添加换行符。)这会发生,直到它获得EOF(文件结束),此时它会升起 EOFError

因此,这是您可以使用的方式 input 在Python 3中(或 raw_input 在Python 2)中从stdin读取 - 所以我们创建一个我们称之为stdindemo.py的Python模块:

$ python -c "print('try:\n    while True:\n        print(input())\nexcept EOFError:\n    pass')" > stdindemo.py 

然后让我们将其打印出来以确保它符合我们的预期:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py 
try:
    while True:
        print(input())
except EOFError:
    pass

再次, input 读取直到换行符并基本上将其从行中删除。 print 添加换行符。因此,虽然他们都修改输入,他们的修改取消。 (所以他们基本上是彼此的补充。)

什么时候 input 获取文件结束字符,它会引发EOFError,我们忽略它然后退出程序。

在Linux / Unix上,我们可以从cat管道:

$ cat inputs.txt | python -m stdindemo
foo
bar
baz

或者我们可以从stdin重定向文件:

$ python -m stdindemo < inputs.txt 
foo
bar
baz

我们也可以将模块作为脚本执行:

$ python stdindemo.py < inputs.txt 
foo
bar
baz

这是内置的帮助 input 来自Python 3:

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.

    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.

    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

sys.stdin

在这里我们使用演示脚本 sys.stdin。迭代类文件对象的有效方法是使用类文件对象作为迭代器。从这个输入写入stdout的补充方法是简单地使用 sys.stdout.write

$ python -c "print('import sys\nfor line in sys.stdin:\n    sys.stdout.write(line)')" > stdindemo2.py

将其打印出来以确保它看起来正确:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py 
import sys
for line in sys.stdin:
    sys.stdout.write(line)

并将输入重定向到文件中:

$ python -m stdindemo2 < inputs.txt
foo
bar
baz

高尔夫球命令:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz

高尔夫文件描述符

由于文件描述符 stdin 和 stdout 分别是0和1,我们也可以将它们传递给 open 在Python 3中(不是2,注意我们仍然需要'w'来写入stdout)。

如果这适用于您的系统,它将削减更多字符。

$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo

Python 2的 io.open 这样做,但导入需要更多的空间:

$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt 
foo
bar
baz

解决其他意见和答案

一条评论表明 ''.join(sys.stdin) 但这实际上比sys.stdin.read()更长 - 加上Python必须在内存中创建一个额外的列表(这就是如何 str.join 没有给出列表时工作) - 对比:

''.join(sys.stdin)
sys.stdin.read()

最佳答案表明:

import fileinput

for line in fileinput.input():
    pass

但是由于 sys.stdin 实现文件API,包括迭代器协议,它与此相同:

import sys

for line in sys.stdin:
    pass

另一个答案  建议这个。请记住,如果你在翻译中这样做,你需要这样做 按Ctrl - d 如果您使用的是Linux或Mac,或者 按Ctrl - ž 在Windows上(之后 输入)将结束文件字符发送到进程。此外,答案表明 print(line)  - 增加了一个 '\n' 到最后 - 使用 print(line, end='') 相反(如果在Python 2中,你需要 from __future__ import print_function)。

真正的用例 fileinput 用于阅读一系列文件。


49
2017-07-29 15:04





这将回显标准输出到标准输出:

import sys
line = sys.stdin.readline()
while line:
    print line,
    line = sys.stdin.readline()

36
2018-01-25 10:26





建立在所有的使用 sys.stdin,如果存在至少一个参数,你还可以执行类似下面的操作来读取参数文件,否则回退到stdin:

import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin    
for line in f:
#     Do your stuff

并用它作为

$ python do-my-stuff.py infile.txt

要么

$ cat infile.txt | python do-my-stuff.py

甚至

$ python do-my-stuff.py < infile.txt

这将使您的Python脚本像许多GNU / Unix程序一样运行 catgrep 和 sed


28
2017-08-27 15:43





以下代码片段将帮助您(它将读取所有stdin阻塞到 EOF,成一个字符串):

import sys
input_str = sys.stdin.read()
print input_str.split()

13
2017-07-20 21:33





尝试这个:

import sys

print sys.stdin.read().upper()

并检查:

$ echo "Hello World" | python myFile.py

7
2017-11-07 10:08