python - barplot - pandas plot
Entrada de consola sin bloqueo de Python (6)
Aquí una solución que se ejecuta en Linux y Windows utilizando un hilo separado:
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()
Estoy intentando hacer un cliente IRC simple en Python (como una especie de proyecto mientras aprendo el idioma).
Tengo un bucle que uso para recibir y analizar lo que el servidor IRC me envía, pero si uso raw_input
para ingresar cosas, detiene el bucle muerto en sus pistas hasta que ingrese algo (obviamente).
¿Cómo puedo ingresar algo sin que el ciclo se detenga?
Gracias por adelantado.
(No creo que deba publicar el código, solo quiero ingresar algo sin que se detenga el ciclo 1 ).
EDITAR: estoy en Windows.
Con python3.3 y superior puede usar el módulo asyncio
como se menciona en esta respuesta. Sin embargo, tendrá que volver a factorizar su código para trabajar con asyncio
. Indicar la entrada del usuario mediante la instancia python asyncio.create_server
Creo que la biblioteca de curses puede ayudar.
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()
En Linux, aquí hay una refactorización del código de Mizipzor que hace que esto sea un poco más fácil, en caso de que tenga que usar este código en varios lugares.
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
Aquí le mostramos cómo usar esto: Este código imprimirá un contador que seguirá creciendo hasta que presione ESC.
with NonBlockingConsole() as nbc:
i = 0
while 1:
print i
i += 1
if nbc.get_data() == ''/x1b'': # x1b is ESC
break
Esta es la solution más asombrosa 1 que he visto en mi vida. Pegado aquí en caso de que el enlace se caiga:
#!/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 Realizado por Simon D. Levy , parte de una compilación de software que ha escrito y publicado bajo la Licencia pública general menor de Gnu .
Para Windows, solo consola, use el módulo 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
Para Linux, este article describe la siguiente solución, requiere el módulo 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)
Para plataforma cruzada, o en caso de que también desee una GUI, puede usar 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