有没有办法从用户输入读取一个单个字符?例如,他们在终端按一个键然后返回(有点像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/Linux(取决于具体终端上,也许?),你也可以得到Insert,Delete,Pg Up,Pg Dn,Home,End和键...但随后,有分离的这些特殊键问题.F nEsc
警告:像在这里的大多数(?全部)答案,信号键,如Ctrl+ C,Ctrl+ D和Ctrl+ 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
来自这篇博文.
此代码基于此处,如果按下Ctrl+ C或Ctrl+ ,将正确引发KeyboardInterrupt和EOFError D.
应该适用于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代码)过于复杂.当一个单纯的功能足够时,我没有看到使用类的理由.下面是两个实现相同但具有更多可读代码的实现.
这两个实现:
在Python 2或Python 3中工作得很好
适用于Windows,OSX和Linux
只读一个字节(即他们不等待换行)
不依赖于任何外部库
是自包含的(函数定义之外没有代码)
版本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异常处理的成本(可忽略不计).虽然您可能应该更关注代码可读性而不是可忽略的优化,但这里有一个替代方案(类似于Louis的答案,但getChar()是自包含的),其功能与ActiveState代码相同,并且更具可读性:
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))