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/)

🌐
DigitalOcean
digitalocean.com › community › tutorials › read-stdin-python
How to Read from stdin in Python | DigitalOcean
August 3, 2022 - Hi Processing Message from sys.stdin ... so that we can check if the user has entered “Exit” message or not. We can also use Python input() function to read the standard input data....
Discussions

python - Read stdin like a dictator - Code Review Stack Exchange
All too often I find myself wanting to allow only a certain list of characters to be written to stdin, and only recently did I actually bother to implement it. In Python, of all languages! Essentially, this module provides a few APIs that allow a very tailored approach to reading characters from a ... More on codereview.stackexchange.com
🌐 codereview.stackexchange.com
February 3, 2016
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 informa... More on stackoverflow.com
🌐 stackoverflow.com
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
python - How do I read from stdin? - Stack Overflow
Here's a complete, easily replicable demo, using two methods, the builtin function, input (use raw_input in Python 2), and sys.stdin. The data is unmodified, so the processing is a non-operation. ... read(size=-1, /) method of _io.TextIOWrapper instance Read at most n characters from stream. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Stack Abuse
stackabuse.com › reading-from-stdin-in-python
Reading from stdin in Python
August 28, 2023 - They are used for inter-process ... through the sys.stdin object, which behaves like a file object. This means you can use methods like read(), readline(), and readlines() to read from stdin, just as you would read from a file....
🌐
GitHub
gist.github.com › payne92 › 11090057
getch() function to read single char from stdin, w/o waiting for newline (Windows and Unix) · GitHub
getch() function to read single char from stdin, w/o waiting for newline (Windows and Unix) - gist:11090057
🌐
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)
import sys, os import termios, fcntl import select fd = sys.stdin.fileno() newattr = termios.tcgetattr(fd) newattr[3] = newattr[3] & ~termios.ICANON newattr[3] = newattr[3] & ~termios.ECHO termios.tcsetattr(fd, termios.TCSANOW, newattr) oldterm = termios.tcgetattr(fd) oldflags = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK) print "Type some stuff" while True: inp, outp, err = select.select([sys.stdin], [], []) c = sys.stdin.read() if c == 'q': break print "-", c # Reset the terminal: termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm) fcntl.fcntl(fd, fcntl.F_SETFL, oldflags) A less minimal example: keyreader.py, a class to read characters, with blocking and echo optional. It also cleans up after itself on exit, though most of the time that seems to happen automatically when I exit the Python script.
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)
🌐
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 - Python read input from stdin. What is stdin? Methods to read input from stdin: using 'input()', using sys module, using fileinput module
Find elsewhere
🌐
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.
🌐
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 - One of the simplest methods to read from stdin is using the Python built-in input() function, which prompts the user to enter input from the keyboard and returns a string containing the input.
🌐
Linux Hint
linuxhint.com › read-from-stdin-in-python
How to Read from stdin in Python – Linux Hint
Many ways exist in python to read from the standard input. The input() function is the most common way is to read from the standard input, which is a built-in function. The sys.stdin is another way is to read from the standard input the calls input() function internally.
🌐
ActiveState
code.activestate.com › recipes › 134892-getch-like-unbuffered-character-reading-from-stdin
getch()-like unbuffered character reading from stdin on both Windows and Unix « Python recipes « ActiveState Code
June 21, 2002 - A small utility class to read single characters from standard input, on both Windows and UNIX systems. It provides a getch() function-like instance. ... old python versions have to include TERMIOS. If you use an old python version (e.g.
🌐
Finxter
blog.finxter.com › home › learn python blog › read from stdin in python
Read from Stdin in Python – Be on the Right Side of Change
February 4, 2022 - One way to read from stdin in Python is to use sys.stdin. The sys.stdin gets input from the command line directly and then calls the input() function internally. It also adds a newline ‘\n’ character automatically after taking the input.
🌐
UltaHost
ultahost.com › knowledge-base › read-from-stdin-python
How to Read From stdin in Python | Ultahost Knowledge Base
March 14, 2025 - Before getting started refer to our guide on how to install Python on your Windows 10 system. The input() function is the simplest way to read input from stdin.
🌐
PhoenixNAP
phoenixnap.com › home › kb › devops and development › how to read from stdin in python
How to Read From stdin in Python | phoenixNAP KB
June 5, 2025 - Learn how to take user input and read from stdin in Python through hands-on examples. This article shows three different methods.