Here's a link to the ActiveState Recipes site that says how you can read a single character in Windows, Linux and OSX:

    getch()-like unbuffered character reading from stdin on both Windows and Unix

class _Getch:
    """Gets a single character from standard input.  Does not echo to the
screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()
Answer from tehvan on Stack Overflow
Top answer
1 of 16
244

Here's a link to the ActiveState Recipes site that says how you can read a single character in Windows, Linux and OSX:

    getch()-like unbuffered character reading from stdin on both Windows and Unix

class _Getch:
    """Gets a single character from standard input.  Does not echo to the
screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()
2 of 16
97
sys.stdin.read(1)

will basically read 1 byte from STDIN.

If you must use the method which does not wait for the \n you can use this code as suggested in previous answer:

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()


getch = _Getch()

(taken from http://code.activestate.com/recipes/134892/)

Discussions

Reading char for char from stdin without waiting for '\n' / new line
This behavior resides outside the C language itself. The solution will be platform dependent and you didn't mention what platform you are on. For example, on Unix and Unix-clones like Linux, your terminal starts in 'cooked' mode and you would need to put it in 'raw' mode. Note that 'cooked' and 'raw' (or canonical/non-canonical) are just two presets for a large collection of tweakable settings related to your terminal. This wikipedia article is a reasonable starting point to learn the lingo so you can search for more info. More on reddit.com
๐ŸŒ r/C_Programming
19
16
June 5, 2022
Python sys.stdin.read(1) in a while(True) loop consistently executes 1 time getting input and multiple times not getting input - Stack Overflow
How do I get Python to read one char at a time in an infinite loop? ... I lied. In PyDev Eclipse calling flush() makes 1 time getting user input and 1 time skipping user input (instead of 2 times). Adding multiple flush() has no other effect. ... Problem is probably due to flushing of stdin since ... More on stackoverflow.com
๐ŸŒ stackoverflow.com
How do you read single chars from stdin in Python - Stack Overflow
There are a lot of great answers on how to read from stdin in python, but I just can't find anything about reading single characters instead of whole lines. Let me explain: I need to read information send by an arduino on a serial port, which is forwarded to stdin. More on stackoverflow.com
๐ŸŒ stackoverflow.com
How would I read a single char at a time from stdin
stdin implements Read trait, check it's methods. do you want to read 1 byte, or 1 unicode character which might be multiple bytes? More on reddit.com
๐ŸŒ r/rust
23
0
November 3, 2023
Top answer
1 of 1
9

I really don't like that you detect which version of _GetchX to use via an ImportError - that isn't obvious to me at all. I also don't like that you keep importing things locally. I think you can solve this like so:

import platform
system = platform.system()    
import sys

if system == "Windows":
    import msvcrt

    class _Getch:
        """Gets a single character from standard input."""

        def __call__(self):
            return msvcrt.getch()

else:
    import tty, termios

    class _Getch: 
        """Gets a single character from standard input."""

        def __call__(self):
            fd = sys.stdin.fileno()
            old_settings = termios.tcgetattr(fd)
            try:
                tty.setraw(sys.stdin.fileno())
                ch = sys.stdin.read(1)
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
            return ch

If that level of repetition is also upsetting, move the if inside of the __call__ implementation, but that seems like too much. You could try this instead:

class _Getch:
    """Gets a single character from standard input."""

if system == "Windows":
    import msvcrt

    def _call(self):
        return msvcrt.getch()

else:
    import tty, termios

    def _call(self):
       fd = sys.stdin.fileno()
       old_settings = termios.tcgetattr(fd)
       try:
           tty.setraw(sys.stdin.fileno())
           ch = sys.stdin.read(1)
       finally:
           termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
           return ch

_Getch.__call__ = _call

More generally, however, I don't understand why this is a class. Just make it a function.

if system == "Windows":
    import msvcrt

    def getch():
        return msvcrt.getch()

else:
    import tty, termios

    def getch():
       fd = sys.stdin.fileno()
       old_settings = termios.tcgetattr(fd)
       try:
           tty.setraw(sys.stdin.fileno())
           ch = sys.stdin.read(1)
       finally:
           termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
           return ch

Why is this a lambda?

parsenum = (lambda num:
        (sys.maxsize if 0 > num else num))

Just make a normal function, for readability if nothing else.

def parsenum(num):
    return sys.maxsize if 0 > num else num

General thoughts on the rest of your code:

Why are you explicitly calling __call__()? Just call it normally (or just use the function, as above). You also have a lot of magic numbers, which to someone who is not immediately familiar with their ASCII codes (I have literally never been able to remember any ASCII code off the top of my head) isn't helpful - prefer named constants here. Instead of ox == 27 or ox == 127 just do ox in [27, 127] (and replace that with some constant). You shouldn't need to explicitly turn chars into a list, unless you expect that it is some bizarre iterable type that doesn't implement __getitem__.

You mentioned in the comments that you assign the result of sys.stdout.write(i) because it will append the result to the output otherwise. I had no idea that happens, and it seems pretty odd, but it looks like a code smell to anyone (like myself) who doesn't know that it happens. You could put a comment everywhere you do that, but that is annoying and you might forget if you add it in the future. I'd write a simple helper method

def write_to_stdout(i):
    # Have to assign or it will append the result to the output
    _ = sys.stdout.write(i)
    sys.stdout.flush()

until and until_not are basically identical - they could be condensed to this:

def _until_condition(chars, condition, count) -> str:
    y = []
    count = parsenum(count)
    while len(y) <= count:
        i = read_single_keypress()
        write_to_stdout(i)
        if condition(i, chars):
            break
        y = nbsp(i, y)
    return "".join(y)

def until(chars, count=-1) -> str:
    """get chars of stdin until any of chars is read,
    or until count chars have been read, whichever comes first"""

    return _until_condition(chars, lambda i, chars: i in chars, count)

def until_not(chars, count=-1) -> str:
    """read stdin until any of chars stop being read,
    or until count chars have been read; whichever comes first"""

    return _until_condition(chars, lambda i, chars: i not in chars, count)
๐ŸŒ
DigitalOcean
digitalocean.com โ€บ community โ€บ tutorials โ€บ read-stdin-python
How to Read from stdin in Python | DigitalOcean
August 3, 2022 - There are three ways to read data from stdin in Python. ... Python sys module stdin is used by the interpreter for standard input. Internally, it calls the input() function. The input string is appended with a newline character (\n) in the end. So, you can use the rstrip() function to remove it.
๐ŸŒ
Reddit
reddit.com โ€บ r/c_programming โ€บ reading char for char from stdin without waiting for '\n' / new line
r/C_Programming on Reddit: Reading char for char from stdin without waiting for '\n' / new line
June 5, 2022 -

Yo, I'm trying to read from stdin char for char and then operate on it. Specifically I would like to be able to stop reading before receiving a new line character, however, the while loop will only terminate once both an 'x' and a new line is received.

    while (1) {
        int ch = getchar();
        if (ch == 'x')
            break;
    }

I have a suspicion getchar() is maybe not what I want to use. There are so many ways to read input and I can't seem to find the best way. Here is exactly what I want to do if anyone would be so kind to help me out more generally:

  • read input buffer from stdin char for char until specific char is typed in (input can can be any string).

  • once specific char is typed in -> flush the screen, do some calculations, and continue reading the input buffer.

Thanks!

๐ŸŒ
PyPI
pypi.org โ€บ project โ€บ readchar
readchar ยท PyPI
Born as a python-inquirer requirement. ... Or download the source code from PyPi. ... from readchar import readkey, key while True: k = readkey() if k == "a": # do stuff if k == key.DOWN: # do stuff if k == key.ENTER: break ... Reads one character from stdin, returning it as a string with length 1.
      ยป pip install readchar
    
Published ย  Nov 04, 2024
Version ย  4.2.1
๐ŸŒ
Shallow Thoughts
shallowsky.com โ€บ blog โ€บ programming โ€บ python-read-characters.html
Reading keypresses in Python (Shallow Thoughts)
Years ago, I found a guide on the official Python Library and Extension FAQ: Python: How do I get a single keypress at a time?. I'd even used it once, for a one-off Raspberry Pi project that I didn't end up using much. I hadn't done much testing of it at the time, but trying it now, I found a big problem: it doesn't block. Blocking is whether the read() waits for input or returns immediately. If I read a character with c = sys.stdin.read(1) but there's been no character typed yet, a non-blocking read will throw an IOError exception, while a blocking read will wait, not returning until the user types a character.
๐ŸŒ
Stack Abuse
stackabuse.com โ€บ reading-from-stdin-in-python
Reading from stdin in Python
August 28, 2023 - Sometimes, you might want to read a specific number of characters from stdin. This can be done using the read() method provided by sys.stdin.
Find elsewhere
๐ŸŒ
Tutorialwing
tutorialwing.com โ€บ home โ€บ python program to read character as input (with example)
Python Program to Read Character as Input (With Example) - Tutorialwing
January 21, 2022 - import sys c = sys.stdin.read(1) print("Entered character: ", c) ... Finally, using print method, we are printing entered value. When you run above program, we will get output as below โ€“ ... Here, 45 is entered value.
๐ŸŒ
Spark By {Examples}
sparkbyexamples.com โ€บ home โ€บ python โ€บ how do you read from stdin in python?
How do you read from stdin in Python? - Spark By {Examples}
May 31, 2024 - If you prefer a more concise way to read input from stdin in Python, you can use the open() function to create a file object that represents stdin, and then use the read() method to read all the input at once as a string.
๐ŸŒ
PythonHow
pythonhow.com โ€บ how โ€บ read-from-stdin-standard-input
Here is how to read from stdin (standard input) in Python
import sys input_text = sys.stdin.read() print("The input was:", input_text)You can also use file object to read from stdin in python like this:
๐ŸŒ
Better Stack
betterstack.com โ€บ community โ€บ questions โ€บ how-to-read-stdin-in-python
How do I read from stdin in Python? | Better Stack Community
October 5, 2023 - In Python, you can read from standard input (stdin) using the input() function. This function blocks execution and waits for the user to enter some text, which is then returned as a string.
๐ŸŒ
Python Forum
python-forum.io โ€บ thread-11862.html
Type just one character not followed by ENTER
Hi all! If I remember well,in C++, I could wait an answer to (y/n), the user typing y, not followed by hitting ENTER. Is it possible in python3 ?? Thanks
๐ŸŒ
Python Pool
pythonpool.com โ€บ home โ€บ blog โ€บ best ways to read input in python from stdin
Best Ways to Read Input in Python From Stdin - Python Pool
August 19, 2022 - Therefore, it only reads four characters from the input. ... You can also read input from stdin line by line.
๐ŸŒ
Lazarus
forum.lazarus.freepascal.org โ€บ index.php
read(input) skips first char & Questions about stdin, and reading stdin to array
October 26, 2020 - read(input) skips first char & Questions about stdin, and reading stdin to array
๐ŸŒ
YouTube
youtube.com โ€บ watch
How to Read Just One Character from the Terminal (stdin)? - YouTube
Patreon โžค https://www.patreon.com/jacobsorberCourses โžค https://jacobsorber.thinkific.comWebsite โžค https://www.jacobsorber.com---How to Read Just One Characte...
Published ย  October 11, 2022
๐ŸŒ
UltaHost
ultahost.com โ€บ knowledge-base โ€บ read-from-stdin-python
How to Read From stdin in Python | Ultahost Knowledge Base
March 14, 2025 - Learn how to read input from stdin in Python using several methods and file redirection. Explore examples and practices for input handling.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python-program-to-read-character-by-character-from-a-file
Python program to read character by character from a file - GeeksforGeeks
September 6, 2024 - Input: Geeks Output: G e e k s Explanation: Iterated through character by character from the input as shown in the output. In this article, we will look into a few examples of reading a file word by word in Python for a better understanding of the concept.