我试图在Python中创建一个简单的IRC客户端(作为一个项目,我学习语言).
我有一个循环,我用它来接收并解析什么IRC服务器发送了我,但如果我用raw_input
输入的东西,它停止循环在它的轨道死,直到我输入的东西(明显).
如何在没有循环停止的情况下输入内容?
提前致谢.
(我不认为我需要发布代码,我只想输入一些没有while 1循环停止的东西.)
编辑:我在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,本文介绍了以下解决方案,它需要以下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
这是最真棒解决方案1我见过.粘贴在这里以防链接断开:
#!/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下运行的解决方案:
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
我认为curses库可以提供帮助。
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()