Неблокирующий консольный вход Python

Я пытаюсь сделать простой IRC-клиент в Python (как вид проекта, в то время как я изучаю язык).

У меня есть цикл, который я использую для получения и анализа того, что посылает мне сервер IRC, но если я использую raw_input для ввода данных, он останавливает цикл мертвым на своих дорожках, пока я не введу что-нибудь (очевидно).

Как я могу ввести что-то без остановки цикла?

Заранее спасибо.

(Я не думаю, что мне нужно опубликовать код, я просто хочу ввести что-то без остановки цикла 1 ).

EDIT: Я нахожусь в Windows.

6 Solutions collect form web for “Неблокирующий консольный вход Python”

Для 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) 

Для кросс-платформы, или если вы хотите использовать графический интерфейс, вы можете использовать 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 

Это самое удивительное решение, которое я когда-либо видел. Вставка здесь в случае, если ссылка идет вниз:

 #!/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 Создано Саймоном Д. Леви , частью компиляции программного обеспечения, которое он написал и выпустил под лицензией Gnu Lesser General Public License .

Здесь решение, которое выполняется под 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() 

С помощью python3.3 и выше вы можете использовать модуль asyncio как указано в этом ответе. Вам придется заново asyncio свой код, хотя для работы с asyncio . Запрос на ввод пользователя с использованием экземпляра asyncio.create_server python

  • Выполнение модулей как скриптов
  • Как выполнить команду командной строки из python
  • Python - события выключения Windows
  • Есть ли способ перечислить все доступные буквы диска в python?
  • Библиотека уведомлений для Windows
  • Python в Windows - как ждать нескольких дочерних процессов?
  • Почему программа Python 2.7 AMD 64, похоже, запускает Python в 32-битном режиме?
  • Развертывание cx_Oracle в Windows
  • Python - лучший язык программирования в мире.