[python] 파이썬은 사용자로부터 단일 문자를 읽습니다

사용자 입력에서 하나의 단일 문자를 읽는 방법이 있습니까? 예를 들어 터미널에서 하나의 키를 누르면 반환됩니다 (정렬 한 정렬 getch()). Windows에 기능이 있다는 것을 알고 있지만 플랫폼 간 무언가를 원합니다.



답변

다음은 Windows, Linux 및 OSX에서 단일 문자를 읽는 방법을 알려주는 사이트 링크입니다. http://code.activestate.com/recipes/134892/

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


답변

sys.stdin.read(1)

기본적으로 STDIN에서 1 바이트를 읽습니다.

기다리지 않는 방법을 사용해야하는 경우 \n이전 답변에서 제안한대로이 코드를 사용할 수 있습니다.

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

( http://code.activestate.com/recipes/134892/ 에서 가져옴 )


답변

두 가지 답변으로 구두 인용 된 ActiveState 레시피 가 과도하게 엔지니어링되었습니다. 다음과 같이 정리할 수 있습니다.

def _find_getch():
    try:
        import termios
    except ImportError:
        # Non-POSIX. Return msvcrt's (Windows') getch.
        import msvcrt
        return msvcrt.getch

    # POSIX system. Create and return a getch that manipulates the tty.
    import sys, tty
    def _getch():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

    return _getch

getch = _find_getch()


답변

readchar 라이브러리도 시도해 볼 가치가 있습니다.이 라이브러리는 부분적으로 다른 답변에서 언급 한 ActiveState 레시피를 기반으로합니다.

설치:

pip install readchar

용법:

import readchar
print("Reading a char:")
print(repr(readchar.readchar()))
print("Reading a key:")
print(repr(readchar.readkey()))

Python 2.7을 사용하여 Windows 및 Linux에서 테스트되었습니다.

Windows에서 문자 또는 ASCII 제어 코드에 매핑에만 키가 지원됩니다 ( Backspace, Enter, Esc, Tab, Ctrl+ 문자 ). GNU / 리눅스 (아마, 정확한 터미널에 따라?) 당신은 또한 얻을 Insert, Delete, Pg Up, Pg Dn, Home, End및 키 …하지만 다음에,에서 이러한 특수 키를 분리 문제가있다 .F nEsc

주의 사항 : 대부분의 (모두?) 답변과 마찬가지로 Ctrl+ C, Ctrl+ DCtrl+ 와 같은 신호 키 Z는 잡히고 반환됩니다 ( 각각 '\x03', '\x04''\x1a'). 프로그램이 중단되기 어려울 수 있습니다.


답변

다른 방법 :

import os
import sys    
import termios
import fcntl

def getch():
  fd = sys.stdin.fileno()

  oldterm = termios.tcgetattr(fd)
  newattr = termios.tcgetattr(fd)
  newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
  termios.tcsetattr(fd, termios.TCSANOW, newattr)

  oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
  fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

  try:        
    while 1:            
      try:
        c = sys.stdin.read(1)
        break
      except IOError: pass
  finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
  return c

에서 이 블로그 게시물 .


답변

here에 기반한이 코드 는 Ctrl+ C또는 Ctrl+ D를 누르면 KeyboardInterrupt 및 EOFError를 올바르게 발생 시킵니다.

Windows 및 Linux에서 작동해야합니다. 원본 소스에서 OS X 버전을 사용할 수 있습니다.

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): 
        char = self.impl()
        if char == '\x03':
            raise KeyboardInterrupt
        elif char == '\x04':
            raise EOFError
        return char

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

    def __call__(self):
        import sys
        import tty
        import 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()


답변

(현재) 최상위 답변 (ActiveState 코드 포함)은 지나치게 복잡합니다. 단순한 함수로 충분할 때 클래스를 사용해야 할 이유가 없습니다. 아래는 동일하지만 더 읽기 쉬운 코드로 달성하는 두 가지 구현입니다.

이 두 가지 구현 모두 :

  1. Python 2 또는 Python 3에서 잘 작동합니다.
  2. Windows, OSX 및 Linux에서 작업
  3. 1 바이트 만 읽습니다 (즉, 개행을 기다리지 않습니다)
  4. 외부 라이브러리에 의존하지 않습니다
  5. 자체 포함 (함수 정의 외부의 코드 없음)

버전 1 : 읽기 쉽고 간단

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

버전 2 : 반복되는 가져 오기 및 예외 처리를 피하십시오.

[편집] ActiveState 코드의 장점 중 하나를 놓쳤습니다. 문자를 여러 번 읽으려는 경우 해당 코드는 Unix와 유사한 시스템에서 Windows 가져 오기 및 ImportError 예외 처리를 반복하는 데 드는 비용을 무시할 수 있습니다. 무시할 수있는 최적화보다 코드 가독성에 더 관심이 있어야하지만 ActiveState 코드와 동일하게 작동하고 더 읽기 쉬운 대안이 있습니다 (Louis의 대답과 비슷하지만 getChar ()는 독립적입니다).

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

위의 getChar () 버전 중 하나를 실행하는 예제 코드 :

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