Python从用户读取一个字符

有没有从用户input中读取单个字符的方法? 例如,他们在terminal按下一个键,并返回(有点像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的方法,您可以按照以前的答案中的build议使用此代码:

 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 配方过度devise。 这可以归结为:

 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.7testingWindows和Linux。

在Windows上,只支持映射到字母或ASCII控制代码的按键( 退格回车EscTabCtrl + 字母 )。 在GNU / Linux(取决于确切的terminal,也许?),你也得到插入删除Pg UpPg DnHomeEndFn键…但是,有问题将这些特殊键与Esc分开。

警告:与此处大多数(所有?)答案一样,会捕获并返回像Ctrl + CCtrl + 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 

从这个博客文章 。

我认为在这一点上它变得非常笨重,在不同的平台上进行debugging是一个很大的混乱。

你最好使用像pyglet,pygame,cocos2d之类的东西 – 如果你正在做一些比这更精细的事情,并且需要视觉效果,或者如果你打算和terminal一起工作的话。

Curses是标准的: http : //docs.python.org/library/curses.html

此代码基于此处 ,如果按下Ctrl + CCtrl + 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. 只读一个字节(即,他们不等待换行符)
  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:避免重复导入和exception处理:

[编辑]我错过了ActiveState代码的一个优点。 如果您打算多次阅读字符,那么该代码将避免在类Unix系统上重复Windows导入和ImportErrorexception处理的(可忽略的)成本。 尽pipe你可能应该比可忽略的优化更关心代码的可读性,但这里有一个替代scheme(类似于Louis的答案,但getChar()是独立的),其function与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)) 

这可能是一个上下文pipe理器的用例。 撇开Windows操作系统的配额,这里是我的build议:

 #!/usr/bin/env python3 # file: 'readchar.py' """ Implementation of a way to get a single character of input without waiting for the user to hit <Enter>. (OS is Linux, Ubuntu 14.04) """ import tty, sys, termios class ReadChar(): def __enter__(self): self.fd = sys.stdin.fileno() self.old_settings = termios.tcgetattr(self.fd) tty.setraw(sys.stdin.fileno()) return sys.stdin.read(1) def __exit__(self, type, value, traceback): termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings) def test(): while True: with ReadChar() as rc: char = rc if ord(char) <= 32: print("You entered character with ordinal {}."\ .format(ord(char))) else: print("You entered character '{}'."\ .format(char)) if char in "^C^D": sys.exit() if __name__ == "__main__": test() 

这里的答案是信息丰富的,但是我也想要一种asynchronous获取按键的方法,并且在单独的事件中按下按键,所有这些都是以线程安全的,跨平台的方式进行的。 PyGame对我来说也太臃肿了。 所以我做了以下(在Python 2.7中,但我怀疑它很容易移植),我想我会在这里分享,以防其他人有用。 我把它存储在一个名为keyPress.py的文件中。

 class _Getch: """Gets a single character from standard input. Does not echo to the screen. From http://code.activestate.com/recipes/134892/""" def __init__(self): try: self.impl = _GetchWindows() except ImportError: try: self.impl = _GetchMacCarbon() except(AttributeError, ImportError): self.impl = _GetchUnix() def __call__(self): return self.impl() class _GetchUnix: def __init__(self): import tty, sys, termios # import termios now or else you'll get the Unix version on the Mac 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() class _GetchMacCarbon: """ A function which returns the current ASCII key that is down; if no ASCII key is down, the null string is returned. The page http://www.mactech.com/macintosh-c/chap02-1.html was very helpful in figuring out how to do this. """ def __init__(self): import Carbon Carbon.Evt #see if it has this (in Unix, it doesn't) def __call__(self): import Carbon if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask return '' else: # # The event contains the following info: # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1] # # The message (msg) contains the ASCII char which is # extracted with the 0x000000FF charCodeMask; this # number is converted to an ASCII character with chr() and # returned # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1] return chr(msg & 0x000000FF) import threading # From https://stackoverflow.com/a/2022629/2924421 class Event(list): def __call__(self, *args, **kwargs): for f in self: f(*args, **kwargs) def __repr__(self): return "Event(%s)" % list.__repr__(self) def getKey(): inkey = _Getch() import sys for i in xrange(sys.maxint): k=inkey() if k<>'':break return k class KeyCallbackFunction(): callbackParam = None actualFunction = None def __init__(self, actualFunction, callbackParam): self.actualFunction = actualFunction self.callbackParam = callbackParam def doCallback(self, inputKey): if not self.actualFunction is None: if self.callbackParam is None: callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,)) else: callbackFunctionThread = threading.Thread(target=self.actualFunction, args=(inputKey,self.callbackParam)) callbackFunctionThread.daemon = True callbackFunctionThread.start() class KeyCapture(): gotKeyLock = threading.Lock() gotKeys = [] gotKeyEvent = threading.Event() keyBlockingSetKeyLock = threading.Lock() addingEventsLock = threading.Lock() keyReceiveEvents = Event() keysGotLock = threading.Lock() keysGot = [] keyBlockingKeyLockLossy = threading.Lock() keyBlockingKeyLossy = None keyBlockingEventLossy = threading.Event() keysBlockingGotLock = threading.Lock() keysBlockingGot = [] keyBlockingGotEvent = threading.Event() wantToStopLock = threading.Lock() wantToStop = False stoppedLock = threading.Lock() stopped = True isRunningEvent = False getKeyThread = None keyFunction = None keyArgs = None # Begin capturing keys. A seperate thread is launched that # captures key presses, and then these can be received via get, # getAsync, and adding an event via addEvent. Note that this # will prevent the system to accept keys as normal (say, if # you are in a python shell) because it overrides that key # capturing behavior. # If you start capture when it's already been started, a # InterruptedError("Keys are still being captured") # will be thrown # Note that get(), getAsync() and events are independent, so if a key is pressed: # # 1: Any calls to get() that are waiting, with lossy on, will return # that key # 2: It will be stored in the queue of get keys, so that get() with lossy # off will return the oldest key pressed not returned by get() yet. # 3: All events will be fired with that key as their input # 4: It will be stored in the list of getAsync() keys, where that list # will be returned and set to empty list on the next call to getAsync(). # get() call with it, aand add it to the getAsync() list. def startCapture(self, keyFunction=None, args=None): # Make sure we aren't already capturing keys self.stoppedLock.acquire() if not self.stopped: self.stoppedLock.release() raise InterruptedError("Keys are still being captured") return self.stopped = False self.stoppedLock.release() # If we have captured before, we need to allow the get() calls to actually # wait for key presses now by clearing the event if self.keyBlockingEventLossy.is_set(): self.keyBlockingEventLossy.clear() # Have one function that we call every time a key is captured, intended for stopping capture # as desired self.keyFunction = keyFunction self.keyArgs = args # Begin capturing keys (in a seperate thread) self.getKeyThread = threading.Thread(target=self._threadProcessKeyPresses) self.getKeyThread.daemon = True self.getKeyThread.start() # Process key captures (in a seperate thread) self.getKeyThread = threading.Thread(target=self._threadStoreKeyPresses) self.getKeyThread.daemon = True self.getKeyThread.start() def capturing(self): self.stoppedLock.acquire() isCapturing = not self.stopped self.stoppedLock.release() return isCapturing # Stops the thread that is capturing keys on the first opporunity # has to do so. It usually can't stop immediately because getting a key # is a blocking process, so this will probably stop capturing after the # next key is pressed. # # However, Sometimes if you call stopCapture it will stop before starting capturing the # next key, due to multithreading race conditions. So if you want to stop capturing # reliably, call stopCapture in a function added via addEvent. Then you are # guaranteed that capturing will stop immediately after the rest of the callback # functions are called (before starting to capture the next key). def stopCapture(self): self.wantToStopLock.acquire() self.wantToStop = True self.wantToStopLock.release() # Takes in a function that will be called every time a key is pressed (with that # key passed in as the first paramater in that function) def addEvent(self, keyPressEventFunction, args=None): self.addingEventsLock.acquire() callbackHolder = KeyCallbackFunction(keyPressEventFunction, args) self.keyReceiveEvents.append(callbackHolder.doCallback) self.addingEventsLock.release() def clearEvents(self): self.addingEventsLock.acquire() self.keyReceiveEvents = Event() self.addingEventsLock.release() # Gets a key captured by this KeyCapture, blocking until a key is pressed. # There is an optional lossy paramater: # If True all keys before this call are ignored, and the next pressed key # will be returned. # If False this will return the oldest key captured that hasn't # been returned by get yet. False is the default. def get(self, lossy=False): if lossy: # Wait for the next key to be pressed self.keyBlockingEventLossy.wait() self.keyBlockingKeyLockLossy.acquire() keyReceived = self.keyBlockingKeyLossy self.keyBlockingKeyLockLossy.release() return keyReceived else: while True: # Wait until a key is pressed self.keyBlockingGotEvent.wait() # Get the key pressed readKey = None self.keysBlockingGotLock.acquire() # Get a key if it exists if len(self.keysBlockingGot) != 0: readKey = self.keysBlockingGot.pop(0) # If we got the last one, tell us to wait if len(self.keysBlockingGot) == 0: self.keyBlockingGotEvent.clear() self.keysBlockingGotLock.release() # Process the key (if it actually exists) if not readKey is None: return readKey # Exit if we are stopping self.wantToStopLock.acquire() if self.wantToStop: self.wantToStopLock.release() return None self.wantToStopLock.release() def clearGetList(self): self.keysBlockingGotLock.acquire() self.keysBlockingGot = [] self.keysBlockingGotLock.release() # Gets a list of all keys pressed since the last call to getAsync, in order # from first pressed, second pressed, .., most recent pressed def getAsync(self): self.keysGotLock.acquire(); keysPressedList = list(self.keysGot) self.keysGot = [] self.keysGotLock.release() return keysPressedList def clearAsyncList(self): self.keysGotLock.acquire(); self.keysGot = [] self.keysGotLock.release(); def _processKey(self, readKey): # Append to list for GetKeyAsync self.keysGotLock.acquire() self.keysGot.append(readKey) self.keysGotLock.release() # Call lossy blocking key events self.keyBlockingKeyLockLossy.acquire() self.keyBlockingKeyLossy = readKey self.keyBlockingEventLossy.set() self.keyBlockingEventLossy.clear() self.keyBlockingKeyLockLossy.release() # Call non-lossy blocking key events self.keysBlockingGotLock.acquire() self.keysBlockingGot.append(readKey) if len(self.keysBlockingGot) == 1: self.keyBlockingGotEvent.set() self.keysBlockingGotLock.release() # Call events added by AddEvent self.addingEventsLock.acquire() self.keyReceiveEvents(readKey) self.addingEventsLock.release() def _threadProcessKeyPresses(self): while True: # Wait until a key is pressed self.gotKeyEvent.wait() # Get the key pressed readKey = None self.gotKeyLock.acquire() # Get a key if it exists if len(self.gotKeys) != 0: readKey = self.gotKeys.pop(0) # If we got the last one, tell us to wait if len(self.gotKeys) == 0: self.gotKeyEvent.clear() self.gotKeyLock.release() # Process the key (if it actually exists) if not readKey is None: self._processKey(readKey) # Exit if we are stopping self.wantToStopLock.acquire() if self.wantToStop: self.wantToStopLock.release() break self.wantToStopLock.release() def _threadStoreKeyPresses(self): while True: # Get a key readKey = getKey() # Run the potential shut down function if not self.keyFunction is None: self.keyFunction(readKey, self.keyArgs) # Add the key to the list of pressed keys self.gotKeyLock.acquire() self.gotKeys.append(readKey) if len(self.gotKeys) == 1: self.gotKeyEvent.set() self.gotKeyLock.release() # Exit if we are stopping self.wantToStopLock.acquire() if self.wantToStop: self.wantToStopLock.release() self.gotKeyEvent.set() break self.wantToStopLock.release() # If we have reached here we stopped capturing # All we need to do to clean up is ensure that # all the calls to .get() now return None. # To ensure no calls are stuck never returning, # we will leave the event set so any tasks waiting # for it immediately exit. This will be unset upon # starting key capturing again. self.stoppedLock.acquire() # We also need to set this to True so we can start up # capturing again. self.stopped = True self.stopped = True self.keyBlockingKeyLockLossy.acquire() self.keyBlockingKeyLossy = None self.keyBlockingEventLossy.set() self.keyBlockingKeyLockLossy.release() self.keysBlockingGotLock.acquire() self.keyBlockingGotEvent.set() self.keysBlockingGotLock.release() self.stoppedLock.release() 

这个想法是,你可以简单地调用keyPress.getKey() ,它将从键盘读取一个键,然后返回它。

如果你想要更多的东西,我做了一个KeyCapture对象。 你可以通过keys = keyPress.KeyCapture()来创build一个。

那么你可以做三件事情:

addEvent(functionName)接受任何addEvent(functionName)一个参数的函数。 然后每次按下某个键时,都会在input该键时使用该键的string调用该函数。 这些都在一个单独的线程中运行,所以你可以阻止你想要的所有内容,它不会混淆KeyCapturer的function,也不会延迟其他事件。

get()以与之前相同的阻塞方式返回密钥。 现在需要这里,因为键现在通过KeyCapture对象被捕获,所以keyPress.getKey()将与该行为相冲突,并且由于一次只能捕获一个键,所以它们都会丢失一些键。 另外,如果用户按下“a”,然后按“b”,则调用get() ,用户按下“c”。 get()调用会立即返回'a',那么如果再次调用它将返回'b',然后'c'。 如果再次调用它,将会阻塞,直到按下另一个键。 这可以确保您不会错过任何按键,如果需要的话可以采用阻止方式。 所以这种方式与之前的keyPress.getKey()有些不同

如果你想要返回getKey()的行为,那么get(lossy=True)就像get() ,只不过它只返回在调用get() 之后按下的键。 所以在上面的例子中, get()会阻塞,直到用户按下'c',然后如果再次调用它,将会阻塞,直到按下另一个键。

getAsync()有点不同。 它被devise用于处理大量事物,然后偶尔返回并检查哪些按键被按下。 因此, getAsync()返回自上次调用getAsync()以来按下的所有按键的列表,按从最旧的按键到最近按下的按键的顺序。 它也不会阻塞,这意味着如果自从上一次调用getAsync()以来没有按下键,则将返回一个空的[]

要真正开始捕获密钥,您需要使用上面制作的keys对象调用keys.startCapture()startCapture是非阻塞的,只是启动一个只logging按键的线程,另一个线程来处理这些按键。 有两个线程可以确保logging按键的线程不会错过任何键。

如果你想停止捕获键,你可以调用keys.stopCapture() ,它将停止捕获键。 但是,由于捕获键是一个阻塞操作,所以在调用stopCapture()之后,线程捕获键可能会捕获另一个键。

为了防止这种情况发生,可以将一个可选parameter passing给一个startCapture(functionName, args) ,该函数只需要检查一个键是否等于'c',然后退出。 这个function之前做的很less很重要,例如,这里的睡眠会导致我们错过按键。

但是,如果在此函数中调用了stopCapture() ,那么键捕获将立即停止,而不再尝试捕获,并且所有的get()调用将立即返回,如果没有键被按下,则返回None。

另外,由于get()getAsync()存储了以前按下的所有键(直到您检索它们),所以可以调用clearGetList()clearAsyncList()来忘记以前按下的键。

请注意, get()getAsync()和事件是独立的,所以如果按下某个键:1.一个正在等待的get()调用将返回该键。 其他等待的电话(如果有的话)将继续等待。 2.该密钥将被存储在获取密钥的队列中,以便有损失的get()将返回不被get()返回的最旧的密钥。 3.所有的事件都会以这个键作为input来触发4.这个键将被存储在getAsync()键的列表中,在这个列表中返回,并且在下一次调用getAsync()被设置为空列表。

如果这一切太过分了,下面是一个示例用例:

 import keyPress import time import threading def KeyPressed(k, printLock): printLock.acquire() print "Event: " + k printLock.release() time.sleep(4) printLock.acquire() print "Event after delay: " + k printLock.release() def GetKeyBlocking(keys, printLock): while keys.capturing(): keyReceived = keys.get() time.sleep(1) printLock.acquire() if not keyReceived is None: print "Block " + keyReceived else: print "Block None" printLock.release() def GetKeyBlockingLossy(keys, printLock): while keys.capturing(): keyReceived = keys.get(lossy=True) time.sleep(1) printLock.acquire() if not keyReceived is None: print "Lossy: " + keyReceived else: print "Lossy: None" printLock.release() def CheckToClose(k, (keys, printLock)): printLock.acquire() print "Close: " + k printLock.release() if k == "c": keys.stopCapture() printLock = threading.Lock() print "Press a key:" print "You pressed: " + keyPress.getKey() print "" keys = keyPress.KeyCapture() keys.addEvent(KeyPressed, printLock) print "Starting capture" keys.startCapture(CheckToClose, (keys, printLock)) getKeyBlockingThread = threading.Thread(target=GetKeyBlocking, args=(keys, printLock)) getKeyBlockingThread.daemon = True getKeyBlockingThread.start() getKeyBlockingThreadLossy = threading.Thread(target=GetKeyBlockingLossy, args=(keys, printLock)) getKeyBlockingThreadLossy.daemon = True getKeyBlockingThreadLossy.start() while keys.capturing(): keysPressed = keys.getAsync() printLock.acquire() if keysPressed != []: print "Async: " + str(keysPressed) printLock.release() time.sleep(1) print "done capturing" 

从我做的简单的testing来看,这对我来说是很好的工作,但是如果我错过了一些东西,我也会很乐意接受别人的反馈。

我也在这里发布。

这是非阻塞,读取一个密钥,并将其存储在keypress.key中。

 import Tkinter as tk class Keypress: def __init__(self): self.root = tk.Tk() self.root.geometry('300x200') self.root.bind('<KeyPress>', self.onKeyPress) def onKeyPress(self, event): self.key = event.char def __eq__(self, other): return self.key == other def __str__(self): return self.key 

在你的程序中

 keypress = Keypress() while something: do something if keypress == 'c': break elif keypress == 'i': print('info') else: print("i dont understand %s" % keypress) 

内置的raw_input应该有所帮助。

 for i in range(3): print ("So much work to do!") k = raw_input("Press any key to continue...") print ("Ok, back to work.") 

用pygame试试这个:

 import pygame pygame.init() // eliminate error, pygame.error: video system not initialized keys = pygame.key.get_pressed() if keys[pygame.K_SPACE]: d = "space key" print "You pressed the", d, "." 

尝试使用这个: http : //home.wlu.edu/~levys/software/kbhit.py它是非阻塞的(这意味着你可以有一个while循环,检测一个按键而不停止它)和跨平台。

 import os # Windows if os.name == 'nt': import msvcrt # Posix (Linux, OS X) else: import sys import termios import atexit from select import select class KBHit: def __init__(self): '''Creates a KBHit object that you can call to do various keyboard things.''' if os.name == 'nt': pass else: # Save the terminal settings self.fd = sys.stdin.fileno() self.new_term = termios.tcgetattr(self.fd) self.old_term = termios.tcgetattr(self.fd) # New terminal setting unbuffered self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) # Support normal-terminal reset at exit atexit.register(self.set_normal_term) def set_normal_term(self): ''' Resets to normal terminal. On Windows this is a no-op. ''' if os.name == 'nt': pass else: termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term) def getch(self): ''' Returns a keyboard character after kbhit() has been called. Should not be called in the same program as getarrow(). ''' s = '' if os.name == 'nt': return msvcrt.getch().decode('utf-8') else: return sys.stdin.read(1) def getarrow(self): ''' Returns an arrow-key code after kbhit() has been called. Codes are 0 : up 1 : right 2 : down 3 : left Should not be called in the same program as getch(). ''' if os.name == 'nt': msvcrt.getch() # skip 0xE0 c = msvcrt.getch() vals = [72, 77, 80, 75] else: c = sys.stdin.read(3)[2] vals = [65, 67, 66, 68] return vals.index(ord(c.decode('utf-8'))) def kbhit(self): ''' Returns True if keyboard character was hit, False otherwise. ''' if os.name == 'nt': return msvcrt.kbhit() else: dr,dw,de = select([sys.stdin], [], [], 0) return dr != [] 

An example to use this:

 import kbhit kb = kbhit.KBHit() while(True): print("Key not pressed") #Do something if kb.kbhit(): #If a key is pressed: k_in = kb.getch() #Detect what key was pressed print("You pressed ", k_in, "!") #Do something kb.set_normal_term() 

Or you could use the getch module from PyPi . But this would block the while loop

The curses package in python can be used to enter "raw" mode for character input from the terminal with just a few statements. Curses' main use is to take over the screen for output, which may not be what you want. This code snippet uses print() statements instead, which are usable, but you must be aware of how curses changes line endings attached to output.

 #!/usr/bin/python3 # Demo of single char terminal input in raw mode with the curses package. import sys, curses def run_one_char(dummy): 'Run until a carriage return is entered' char = ' ' print('Welcome to curses', flush=True) while ord(char) != 13: char = one_char() def one_char(): 'Read one character from the keyboard' print('\r? ', flush= True, end = '') ## A blocking single char read in raw mode. char = sys.stdin.read(1) print('You entered %s\r' % char) return char ## Must init curses before calling any functions curses.initscr() ## To make sure the terminal returns to its initial settings, ## and to set raw mode and guarantee cleanup on exit. curses.wrapper(run_one_char) print('Curses be gone!') 

A comment in one of the other answers mentioned cbreak mode, which is important for Unix implementations because you generally don't want ^C ( KeyboardError ) to be consumed by getchar (as it will when you set the terminal to raw mode, as done by most other answers).

Another important detail is that if you're looking to read one character and not one byte , you should read 4 bytes from the input stream, as that's the maximum number of bytes a single character will consist of in UTF-8 (Python 3+). Reading only a single byte will produce unexpected results for multi-byte characters such as keypad arrows.

Here's my changed implementation for Unix:

 import contextlib import os import sys import termios import tty _MAX_CHARACTER_BYTE_LENGTH = 4 @contextlib.contextmanager def _tty_reset(file_descriptor): """ A context manager that saves the tty flags of a file descriptor upon entering and restores them upon exiting. """ old_settings = termios.tcgetattr(file_descriptor) try: yield finally: termios.tcsetattr(file_descriptor, termios.TCSADRAIN, old_settings) def get_character(file=sys.stdin): """ Read a single character from the given input stream (defaults to sys.stdin). """ file_descriptor = file.fileno() with _tty_reset(file_descriptor): tty.setcbreak(file_descriptor) return os.read(file_descriptor, _MAX_CHARACTER_BYTE_LENGTH) 

My solution for python3, not depending on any pip packages.

 # precondition: import tty, sys def query_yes_no(question, default=True): """ Ask the user a yes/no question. Returns immediately upon reading one-char answer. Accepts multiple language characters for yes/no. """ if not sys.stdin.isatty(): return default if default: prompt = "[Y/n]?" other_answers = "n" else: prompt = "[y/N]?" other_answers = "yjosiá" print(question,prompt,flush= True,end=" ") oldttysettings = tty.tcgetattr(sys.stdin.fileno()) try: tty.setraw(sys.stdin.fileno()) return not sys.stdin.read(1).lower() in other_answers except: return default finally: tty.tcsetattr(sys.stdin.fileno(), tty.TCSADRAIN , oldttysettings) sys.stdout.write("\r\n") tty.tcdrain(sys.stdin.fileno())