Python非阻塞控制台input

我正在尝试在Python中创build一个简单的IRC客户端(当我学习这个语言的时候,就像一个项目一样)。

我有一个循环,我用来接收和parsing什么IRC服务器发送给我,但如果我使用raw_inputinput的东西,它停止死循环直到我input的东西(显然)。

我怎样才能input一些没有循环停止?

提前致谢。

(我不认为我需要发布的代码,我只是想input一些没有while循环停止。

编辑:我在Windows上。

对于Windows,仅限控制台,请使用msvcrt模块:

 import msvcrt num = 0 done = False while not done: print num num += 1 if msvcrt.kbhit(): print "you pressed",msvcrt.getch(),"so now i will quit" done = True 

对于Linux, 本文介绍了以下解决scheme,它需要termios模块:

 import sys import select import tty import termios def isData(): return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []) old_settings = termios.tcgetattr(sys.stdin) try: tty.setcbreak(sys.stdin.fileno()) i = 0 while 1: print i i += 1 if isData(): c = sys.stdin.read(1) if c == '\x1b': # x1b is ESC break finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) 

对于跨平台,或者你也想要一个GUI,你可以使用Pygame:

 import pygame from pygame.locals import * def display(str): text = font.render(str, True, (255, 255, 255), (159, 182, 205)) textRect = text.get_rect() textRect.centerx = screen.get_rect().centerx textRect.centery = screen.get_rect().centery screen.blit(text, textRect) pygame.display.update() pygame.init() screen = pygame.display.set_mode( (640,480) ) pygame.display.set_caption('Python numbers') screen.fill((159, 182, 205)) font = pygame.font.Font(None, 17) num = 0 done = False while not done: display( str(num) ) num += 1 pygame.event.pump() keys = pygame.key.get_pressed() if keys[K_ESCAPE]: done = True 

这是我见过的最棒的解决scheme 。 如果连接断开,粘贴在这里:

 #!/usr/bin/env python ''' A Python class implementing KBHIT, the standard keyboard-interrupt poller. Works transparently on Windows and Posix (Linux, Mac OS X). Doesn't work with IDLE. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ''' 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 != [] # Test if __name__ == "__main__": kb = KBHit() print('Hit any key, or ESC to exit') while True: if kb.kbhit(): c = kb.getch() if ord(c) == 27: # ESC break print(c) kb.set_normal_term() 

1由Simon D. Levy制作 ,他是根据Gnu较低通用公共许可证编写和发布的软件汇编的一部分。

这里使用一个独立的线程在Linux和Windows下运行的解决scheme:

 import sys import threading import time import Queue def add_input(input_queue): while True: input_queue.put(sys.stdin.read(1)) def foobar(): input_queue = Queue.Queue() input_thread = threading.Thread(target=add_input, args=(input_queue,)) input_thread.daemon = True input_thread.start() last_update = time.time() while True: if time.time()-last_update>0.5: sys.stdout.write(".") last_update = time.time() if not input_queue.empty(): print "\ninput:", input_queue.get() foobar() 

在Linux上,这是一个重构mizipzor的代码,这使得这个更容易,以防万一你必须在多个地方使用这个代码。

 import sys import select import tty import termios class NonBlockingConsole(object): def __enter__(self): self.old_settings = termios.tcgetattr(sys.stdin) tty.setcbreak(sys.stdin.fileno()) return self def __exit__(self, type, value, traceback): termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old_settings) def get_data(self): if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): return sys.stdin.read(1) return False 

这里是如何使用这个:这个代码将打印一个计数器,不断增长,直到你按下ESC。

 with NonBlockingConsole() as nbc: i = 0 while 1: print i i += 1 if nbc.get_data() == '\x1b': # x1b is ESC break 

我认为诅咒图书馆可以帮助。

 import curses import datetime stdscr = curses.initscr() curses.noecho() stdscr.nodelay(1) # set getch() non-blocking stdscr.addstr(0,0,"Press \"p\" to show count, \"q\" to exit...") line = 1 try: while 1: c = stdscr.getch() if c == ord('p'): stdscr.addstr(line,0,"Some text here") line += 1 elif c == ord('q'): break """ Do more things """ finally: curses.endwin() 

使用python3.3及以上版本,您可以使用本答案中提到的asyncio模块。 你将不得不重新考虑你的代码,以使用asyncio 。 使用python asyncio.create_server实例提示用户input