Python sys.stdin.readline() 在没有提示的情况下读取,返回“中间没有任何内容”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21086736/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 22:01:55  来源:igfitidea点击:

sys.stdin.readline() reads without prompt, returning 'nothing in between'

pythonpython-3.xstdin

提问by lightandlight

I have a function that executes the following (among other things):

我有一个执行以下操作的函数(除其他外):

userinput = stdin.readline()
betAmount = int(userinput)

Is supposed to take input integer from stdin as a string and convert it to an integer.

应该将来自 stdin 的输入整数作为字符串并将其转换为整数。

When I call the function, however, it returns a single newline character (it doesn't even wait for me to input anything).

但是,当我调用该函数时,它返回一个换行符(它甚至不等我输入任何内容)。

Earlier in the program I get some input in the form of:

在程序的早期,我以以下形式获得一些输入:

stdin.read(1)

to capture a single character.

捕获单个字符。

Could this have something to do with it? Am I somehow writing a newline character to the next line of stdin?

这可能与它有关吗?我是否以某种方式在标准输入的下一行写了一个换行符?

How can I fix this?

我怎样才能解决这个问题?

采纳答案by Simon

stdin.read(1)reads one character from stdin. If there was more than one character to be read at that point (e.g. the newline that followed the one character that was read in) then that character or characters will still be in the buffer waiting for the next read()or readline().

stdin.read(1)从 中读取一个字符stdin。如果在那一点要读取多个字符(例如,跟在读入的一个字符后面的换行符),那么该字符或多个字符仍将在缓冲区中等待下一个read()readline()

As an example, given rd.py:

例如,给定rd.py

from sys import stdin

x = stdin.read(1)
userinput = stdin.readline()
betAmount = int(userinput)
print ("x=",x)
print ("userinput=",userinput)
print ("betAmount=",betAmount)

... if I run this script as follows (I've typed in the 234):

...如果我按如下方式运行这个脚本(我已经输入了234):

C:\>python rd.py
234
x= 2
userinput= 34

betAmount= 34

... so the 2is being picked up first, leaving the 34and the trailing newline character to be picked up by the readline().

... 所以2首先被拾取,留下34和尾随的换行符由readline().

I'd suggest fixing the problem by using readline()rather than read()under most circumstances.

我建议通过使用readline()而不是read()在大多数情况下解决问题。

回答by Reuben

Try this ...

尝试这个 ...

import sys
buffer = []
while True:
    userinput = sys.stdin.readline().rstrip('\n')
    if userinput == 'quit':
        break
    else:
        buffer.append(userinput)

回答by volcano

stdin.read(1)

will not return when you press one character - it will wait for '\n'. The problem is that the second character is buffered in standard input, and the moment you call another input - it will return immediately because it gets its input from buffer.

当您按下一个字符时不会返回 - 它会等待 '\n'。问题是第二个字符缓冲在标准输入中,当您调用另一个输入时 - 它会立即返回,因为它从缓冲区获取输入。

回答by Jagat

import sys
userinput = sys.stdin.readline()
betAmount = int(userinput)

print betAmount

This works on my system. I checked int('23\n') would result in 23.

这适用于我的系统。我检查了 int('23\n') 会导致 23。

回答by abarnert

Simon's answer and Volcano's together explain what you're doing wrong, and Simon explains how you can fix it by redesigning your interface.

Simon 的回答和 Volcano 的回答一起解释了你做错了什么,Simon 解释了如何通过重新设计界面来修复它。

But if you really needto read 1 character, and then later read 1 line, you can do that. It's not trivial, and it's different on Windows vs. everything else.

但是,如果您确实需要读取 1 个字符,然后再读取 1 行,则可以这样做。这不是微不足道的,它在 Windows 上与其他一切都不同。

There are actually three cases: a Unix tty, a Windows DOS prompt, or a regular file (redirected file/pipe) on either platform. And you have to handle them differently.

实际上存在三种情况:Unix tty、Windows DOS 提示符或任一平台上的常规文件(重定向文件/管道)。你必须以不同的方式处理它们。

First, to check if stdin is a tty (both Windows and Unix varieties), you just call sys.stdin.isatty(). That part is cross-platform.

首先,要检查 stdin 是否为 tty(Windows 和 Unix 版本),只需调用sys.stdin.isatty(). 那部分是跨平台的。

For the non-tty case, it's easy. It may actually just work. If it doesn't, you can just read from the unbuffered object underneath sys.stdin. In Python 3, this just means sys.stdin.buffer.raw.read(1)and sys.stdin.buffer.raw.readline(). However, this will get you encoded bytes, rather than strings, so you will need to call .decode(sys.stdin.decoding)on the results; you can wrap that all up in a function.

对于非 tty 情况,这很容易。它实际上可能只是工作。如果没有,您可以从sys.stdin. 在 Python 3 中,这只是意味着sys.stdin.buffer.raw.read(1)sys.stdin.buffer.raw.readline()。但是,这将为您编码字节,而不是字符串,因此您需要调用.decode(sys.stdin.decoding)结果;您可以将所有这些都包装在一个函数中。

For the tty case on Windows, however, input will still be line buffered even on the raw buffer. The only way around this is to use the Console I/Ofunctions instead of normal file I/O. So, instead of stdin.read(1), you do msvcrt.getwch().

然而,对于 Windows 上的 tty 情况,即使在原始缓冲区上,输入仍将被行缓冲。解决这个问题的唯一方法是使用控制台 I/O功能而不是普通的文件 I/O。所以,而不是stdin.read(1),你做msvcrt.getwch()

For the tty case on Unix, you have to set the terminal to raw mode instead of the usual line-discipline mode. Once you do that, you can use the same sys.stdin.buffer.read(1), etc., and it will just work. If you're willing to do that permanently (until the end of your script), it's easy, with the tty.setrawfunction. If you want to return to line-discipline mode later, you'll need to use the termiosmodule. This looks scary, but if you just stash the results of termios.tcgetattr(sys.stdin.fileno())before calling setraw, then do termios.tcsetattr(sys.stdin.fileno(), TCSAFLUSH, stash), you don't have to learn what all those fiddly bits mean.

对于 Unix 上的 tty 情况,您必须将终端设置为原始模式,而不是通常的 line-discipline 模式。一旦你这样做了,你可以使用相同的sys.stdin.buffer.read(1),等等,它就会起作用。如果您愿意永久执行此操作(直到脚本结束),那么使用该tty.setraw函数很容易。如果您想稍后返回学科模式,则需要使用该termios模块。这看起来很可怕,但是如果您只是termios.tcgetattr(sys.stdin.fileno())在调用 之前存储结果setraw,然后执行termios.tcsetattr(sys.stdin.fileno(), TCSAFLUSH, stash),您就不必了解所有这些繁琐的位的含义。

On both platforms, mixing console I/O and raw terminal mode is painful. You definitely can't use the sys.stdinbuffer if you've ever done any console/raw reading; you can only use sys.stdin.buffer.raw. You could always replace readlineby reading character by character until you get a newline… but if the user tries to edit his entry by using backspace, arrows, emacs-style command keys, etc., you're going to get all those as raw keypresses, which you don't want to deal with.

在两个平台上,混合控制台 I/O 和原始终端模式是痛苦的。sys.stdin如果你曾经做过任何控制台/原始阅读,你绝对不能使用缓冲区;你只能使用sys.stdin.buffer.raw. 您总是可以readline通过逐个字符读取来替换,直到出现换行符……但是如果用户尝试使用退格、箭头、emacs 样式的命令键等来编辑他的条目,您将获得所有这些作为原始按键,你不想处理。

回答by ale5000

If you need just one character and you don't want to keep things in the buffer, you can simply read a whole line and drop everything that isn't needed.

如果您只需要一个字符并且不想将内容保留在缓冲区中,则可以简单地读取一整行并删除不需要的所有内容。

Replace:

代替:

stdin.read(1)

with

stdin.readline().strip()[:1]

This will read a line, remove spaces and newlines and just keep the first character.

这将读取一行,删除空格和换行符,只保留第一个字符。