How to read a single character from the user?

后端 未结 23 2680
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-21 04:28

Is there a way of reading one single character from the user input? For instance, they press one key at the terminal and it is returned (sort of like getch()).

23条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-21 05:07

    The (currently) top-ranked answer (with the ActiveState code) is overly complicated. I don't see a reason to use classes when a mere function should suffice. Below are two implementations that accomplish the same thing but with more readable code.

    Both of these implementations:

    1. work just fine in Python 2 or Python 3
    2. work on Windows, OSX, and Linux
    3. read just one byte (i.e., they don't wait for a newline)
    4. don't depend on any external libraries
    5. are self-contained (no code outside of the function definition)

    Version 1: readable and simple

    def getChar():
        try:
            # for Windows-based systems
            import msvcrt # If successful, we are on Windows
            return msvcrt.getch()
    
        except ImportError:
            # for POSIX-based systems (with termios & tty support)
            import tty, sys, termios  # raises ImportError if unsupported
    
            fd = sys.stdin.fileno()
            oldSettings = termios.tcgetattr(fd)
    
            try:
                tty.setcbreak(fd)
                answer = sys.stdin.read(1)
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)
    
            return answer
    

    Version 2: avoid repeated imports and exception handling:

    [EDIT] I missed one advantage of the ActiveState code. If you plan to read characters multiple times, that code avoids the (negligible) cost of repeating the Windows import and the ImportError exception handling on Unix-like systems. While you probably should be more concerned about code readability than that negligible optimization, here is an alternative (it is similar to Louis's answer, but getChar() is self-contained) that functions the same as the ActiveState code and is more readable:

    def getChar():
        # figure out which function to use once, and store it in _func
        if "_func" not in getChar.__dict__:
            try:
                # for Windows-based systems
                import msvcrt # If successful, we are on Windows
                getChar._func=msvcrt.getch
    
            except ImportError:
                # for POSIX-based systems (with termios & tty support)
                import tty, sys, termios # raises ImportError if unsupported
    
                def _ttyRead():
                    fd = sys.stdin.fileno()
                    oldSettings = termios.tcgetattr(fd)
    
                    try:
                        tty.setcbreak(fd)
                        answer = sys.stdin.read(1)
                    finally:
                        termios.tcsetattr(fd, termios.TCSADRAIN, oldSettings)
    
                    return answer
    
                getChar._func=_ttyRead
    
        return getChar._func()
    

    Example code that exercises either of the getChar() versions above:

    from __future__ import print_function # put at top of file if using Python 2
    
    # Example of a prompt for one character of input
    promptStr   = "Please give me a character:"
    responseStr = "Thank you for giving me a '{}'."
    print(promptStr, end="\n> ")
    answer = getChar()
    print("\n")
    print(responseStr.format(answer))
    

提交回复
热议问题