Sys.stdin.readline() читает без подсказки, возвращая "ничего между",
У меня есть функция, которая выполняет следующее (между прочим):
userinput = stdin.readline()
betAmount = int(userinput)
Предполагается взять входное целое из stdin в виде строки и преобразовать его в целое число.
Однако, когда я вызываю эту функцию, он возвращает один символ новой строки (он даже не дожидается ввода чего-либо).
Ранее в программе я получаю некоторый ввод в виде:
stdin.read(1)
для захвата одного символа.
Может ли это иметь к этому какое-то отношение? Я как-то пишу символ новой строки для следующей строки stdin?
Как я могу это исправить?
Ответы
Ответ 1
stdin.read(1)
читает один символ из stdin
. Если в этот момент было прочитано более одного символа (например, новая строка, следующая за одним символом, который был прочитан), этот символ или символы все равно будут находиться в буфере, ожидающем следующего read()
или readline()
.
В качестве примера, учитывая 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)
... если я запустил этот script следующим образом (я набрал 234
):
C:\>python rd.py
234
x= 2
userinput= 34
betAmount= 34
... поэтому сначала подбирается 2
, оставляя символ 34
и возвращающийся символ новой строки под readline()
.
Я предлагаю устранить проблему, используя readline()
, а не read()
в большинстве случаев.
Ответ 2
Ответ Саймона и Volcano вместе объясняют, что вы делаете неправильно, и Саймон объясняет, как вы можете исправить это, изменив интерфейс.
Но если вам действительно нужно прочитать 1 символ, а затем прочитать 1 строку, вы можете это сделать. Это не тривиально, и он отличается от Windows и всего остального.
На самом деле есть три случая: Unix tty, приглашение Windows DOS или обычный файл (перенаправленный файл/труба) на любой платформе. И вы должны обращаться с ними по-разному.
Во-первых, чтобы проверить, является ли stdin tty (как сортами Windows, так и Unix), вы просто вызываете sys.stdin.isatty()
. Эта часть является кросс-платформенной.
Для случая не-tty это легко. На самом деле это может сработать. Если это не так, вы можете просто прочитать из небуферизованного объекта под sys.stdin
. В Python 3 это просто означает sys.stdin.buffer.raw.read(1)
и sys.stdin.buffer.raw.readline()
. Однако это приведет к кодированию байтов, а не к строкам, поэтому вам нужно будет вызвать .decode(sys.stdin.decoding)
по результатам; вы можете обернуть все это функцией.
Однако для случая tty в Windows вход по-прежнему будет буферизироваться даже в необработанном буфере. Единственный способ обойти это - использовать функции Консоль ввода-вывода вместо обычного ввода-вывода файлов. Итак, вместо stdin.read(1)
вы делаете msvcrt.getwch()
.
Для случая tty в Unix вы должны установить терминал в режим raw вместо обычного режима линии. Как только вы это сделаете, вы можете использовать те же sys.stdin.buffer.read(1)
и т.д., И он будет работать. Если вы готовы сделать это надолго (до конца вашего script), легко, с помощью функции tty.setraw
. Если вы хотите вернуться в режим линейной дисциплины позже, вам нужно будет использовать модуль termios
. Это выглядит страшно, но если вы просто запустили результаты termios.tcgetattr(sys.stdin.fileno())
перед вызовом setraw
, тогда сделайте termios.tcsetattr(sys.stdin.fileno(), TCSAFLUSH, stash)
, вам не нужно узнавать, что означают все эти значащие биты.
На обеих платформах микшерный пульт ввода-вывода и режим raw-терминала болезненны. Вы определенно не можете использовать буфер sys.stdin
, если вы когда-либо делали консольное/сырое чтение; вы можете использовать только sys.stdin.buffer.raw
. Вы всегда можете заменить readline
, прочитав символ по символу, пока не получите новую строку... но если пользователь попытается отредактировать свою запись с помощью backspace, стрелок, командных клавиш стиля emacs и т.д., Вы получите все эти как сырые ключевые слова, с которыми вы не хотите иметь дело.
Ответ 3
stdin.read(1)
не вернется, когда вы нажмете один символ - он будет ждать '\n'. Проблема в том, что второй символ буферизуется в стандартном вводе, а в тот момент, когда вы вызываете другой вход - он немедленно возвращается, потому что он получает свой вход из буфера.
Ответ 4
Попробуйте это...
import sys
buffer = []
while True:
userinput = sys.stdin.readline().rstrip('\n')
if userinput == 'quit':
break
else:
buffer.append(userinput)
Ответ 5
Если вам нужен только один символ, и вы не хотите хранить вещи в буфере, вы можете просто прочитать целую строку и отбросить все, что не нужно.
Заменить:
stdin.read(1)
с
stdin.readline().strip()[:1]
Это прочитает строку, удалит пробелы и символы новой строки и просто сохранит первый символ.
Ответ 6
import sys
userinput = sys.stdin.readline()
betAmount = int(userinput)
print betAmount
Это работает в моей системе. Я проверил int ('23\n '), что приведет к 23.