sys.stdin和input()之间的冲突-EOFError:读取行时遇到EOF

6

我无法让以下脚本正常运行,每次都会抛出EOFError异常:

#!/usr/bin/env python3

import json
import sys

# usage:
# echo '[{"testname": "testval"}]' | python3 test.py

myjson = json.load(sys.stdin)
print(json.dumps(myjson))

answer = input("> ")  # BUG: EOFError: EOF when reading a line
print(answer)

我读了这个问题,它似乎与之相关:Python STDIN User Input Issue
我认为这告诉我需要清除stdin缓冲区?但我不确定如何做到这一点,因为print(sys.stdin.readline())只输出一个换行符,而EOFError仍然存在。
我还尝试使用sys.stdin.flush()方法(在这个问题中找到:Usage of sys.stdout.flush() method),虽然我仍然不明白它的作用,因为我在官方文档(3.6)中找不到它,我找到的最接近的是这个,但它没有提到flush:https://docs.python.org/3/library/sys.html 请记住,我不是程序员,也没有计算机科学的教育或背景。我只是编写脚本来自动化我的非技术性工作的某些部分。因此,如果您知道任何关于在Python中使用shell的stdin/stdout的好的入门资源,请告诉我。

json.load(sys.stdin) 消耗了标准输入中所有可用的数据。没有剩余可读取的内容,因此出现了 EOF。 - melpomene
2个回答

5
通过使用管道输入,Python 将 sys.stdin 作为 FIFO 打开。否则,Python 将打开 sys.stdin 到 /dev/tty 或等效位置。
您可以通过以下方式验证:
import os,sys,stat
print("isatty():", sys.stdin.isatty())
print("isfifo():", stat.S_ISFIFO(os.fstat(0).st_mode))

运行两次,一次输入数据,一次不输入。

我得到:

$ echo "Test" | ./test2.py
isatty(): False
isfifo(): True

$ ./test2.py
isatty(): True
isfifo(): False

你的 EOF 错误是因为 FIFO sys.stdin 被打开到一个空值 is

不过,你可以重新打开 sys.stdin 到 /dev/tty

j = json.load(sys.stdin)
print(j)

sys.stdin = open("/dev/tty")

answer = input("> ")
print(answer)

这个方案能很好的解决问题:

$ echo '{"key":"val"}' | python3 ./testjson.py
{'key': 'val'}
> testing
testing

哈哈,我应该把“非程序员”这部分加粗,有很多东西我需要研究才能理解发生了什么,但它完美地运行了。非常感谢你的解释和解决方案! - rmercier
请不要担心无法理解这个(真的)。这种情况很少发生,而且即使发生了也会非常令人困惑。 - jedwards
非常感谢@jedwards,我希望SO和Google在我花费数小时寻找优秀解决方案之前,能够首先展示您的答案 :) - Edgar Manukyan

0

你不能真正地“清除”标准输入(stdin)。它一直在那里,可供读取,许多输入函数会一直读取直到文件结束(EOF,或标准输入的结尾)。"刷新"操作是针对标准输出的。

在你的情况下,json.load(sys.stdin)操作将读取整个标准输入(然后它将被关闭)。此时,没有更多的输入可用。

如果你既想读取输入数据又想从用户进行交互式输入,请考虑从文件中读取数据,并仅使用标准输入进行交互式用户输入。


谢谢您详尽的解释!我正在编写一个脚本,需要在第三方程序将JSON字符串导出到stdout后执行。而且我无法更改这个第三方程序的操作方式(例如让它将JSON写入文件)。但我还需要用户手动接受一些JSON字典并丢弃其他字典。在Python中没有办法做到这样吗? - rmercier
也许你可以将第三方脚本的JSON输出导入到一个临时文件中,然后将该文件提供给你的程序。通常情况下,在Python或任何语言中,你不能同时使用标准输入来读取文件和读取用户输入。 - payne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接