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.