2010-10-01 10 views
4

J'ai un script qui s'exécute de façon continue quand on l'appelle et toutes les 5 minutes vérifie ma boîte de réception gmail. Pour l'exécuter toutes les 5 minutes, j'utilise la fonction time.sleep(). Cependant, je voudrais que l'utilisateur termine le script à tout moment en appuyant sur q, ce qui semble ne pas pouvoir être fait lors de l'utilisation de time.sleep(). Des suggestions sur comment je peux le faire?Boucle continue et sortie en python

Ali

+0

Out de la curiosité, pourquoi ne pas utiliser [Gmail Notifier] (http://toolbar.google.com/gmail-helper/notifier_windows.html)? – JoshD

+1

Utilisez deux threads? Un qui bloque sur l'entrée de l'utilisateur et un autre qui exécute les contrôles. –

+0

Essayez [libgmail] (http://libgmail.sourceforge.net/) – Emil

Répondre

0

Si vous voulez vraiment (et je voulais perdre beaucoup de ressources), vous pouvez couper votre boucle en 200 ms morceaux. Alors dormez 200 ms, vérifiez l'entrée, répétez jusqu'à cinq minutes, puis vérifiez votre boîte de réception. Je ne le recommanderais pas, cependant.

Pendant qu'il est en veille, le processus est bloqué et ne recevra aucune entrée avant la fin du sommeil. Oh, comme note ajoutée, si vous appuyez sur la touche pendant qu'elle dort, elle devrait toujours entrer dans la mémoire tampon, donc elle sera retirée quand le sommeil se terminera et que l'entrée sera finalement lue, IIRC.

+0

Quelle serait une meilleure façon d'implémenter ce script? Pour qu'il fonctionne continuellement et vérifie mon gmail toutes les 5 minutes. – Ali

+0

Sleep 300 ms, vérifiez l'entrée au clavier, répétez ces deux étapes 1000 fois. Ensuite, vérifiez Gmail. – JoshD

3

Vous pouvez utiliser select() sur sys.stdin combiné avec un délai d'expiration. En gros, votre boucle principale ressemblera à ceci (non testé):

while True: 
    r,w,e = select.select([sys.stdin], [], [], 600) 
    if sys.stdin in r: # data available on sys.stdin 
     if sys.stdin.read() == 'q': 
      break 
    # do gmail stuff 

Pour pouvoir lire un seul caractère de stdin vous aurez besoin de mettre stdin en mode unbuffered. Une alternative est décrite here. Si vous voulez garder les choses simples, il suffit de demander à l'utilisateur de taper enter après le '0'

L'indicateur -u que j'ai mentionné précédemment ne fonctionnera pas: il peut mettre pyton en mode unbuffered mais pas votre terminal.

Alternativement, ncursus peut être utile ici. Je fais simplement allusion, je n'ai pas beaucoup d'expérience avec ceci; Si je veux une interface utilisateur sophistiquée, j'utiliserais TkInter.

+0

Ivo ... J'ai manqué votre lien la première fois. Mon message a été copié/modifié à partir de la même source. Cependant, je ne peux pas obtenir python pour fonctionner normalement en mode unbuffered en utilisant votre morceau de code ... une idée de ce qui pourrait être faux avec l'option -u? – Rajan

+0

-u ne fonctionnera pas, j'ai juste essayé. J'ai mis à jour le post. Si vous voulez vraiment unbuffered, utilisez la magie termios ou (éventuellement) (n) curses –

+1

sélectionnez ne fonctionne que sur les sockets dans les fenêtres – aaronasterling

1

Ok. essayez ce code python ... (testé sous Linux plus probablement ne fonctionnera pas sur Windows -. grâce à l'entrée d'Aaron sur ce)

Cette dérive (copié et modifié) de http://code.activestate.com/recipes/572182-how-to-implement-kbhit-on-linux/


import sys, termios, atexit 
from select import select 

delay = 1 # in seconds - change this for your needs 

# save the terminal settings 
fd = sys.stdin.fileno() 
new_term = termios.tcgetattr(fd) 
old_term = termios.tcgetattr(fd) 

# new terminal setting unbuffered 
new_term[3] = (new_term[3] & ~termios.ICANON & ~termios.ECHO) 

# switch to normal terminal 
def set_normal_term(): 
    termios.tcsetattr(fd, termios.TCSAFLUSH, old_term) 

# switch to unbuffered terminal 
def set_curses_term(): 
    termios.tcsetattr(fd, termios.TCSAFLUSH, new_term) 

def getch(): 
    return sys.stdin.read(1) 

def kbhit(): 
    dr,dw,de = select([sys.stdin], [], [], delay) 
    return dr <> [] 

def check_mail(): 
    print 'Checking mail' 

if __name__ == '__main__': 
    atexit.register(set_normal_term) 
    set_curses_term() 

    while 1: 
     if kbhit(): 
      ch = getch() 
      break 
     check_mail() 

    print 'done' 
+0

malheureusement «select» ne fonctionne que sur les sockets dans les fenêtres. Encore une raison de l'éviter. – aaronasterling

+0

@Aaron: Ce morceau de code fonctionne très bien sur ma machine Ubuntu. Ou vouliez-vous dire sélectionner ne fonctionne que sur Linux? – Rajan

+0

Je voulais dire que ça ne marche que sur nix comme on pourrait s'y attendre.Sur Windows, il ne fonctionne que sur les sockets.J'ai juste vérifié le manuel, mais Termios ne fonctionne que sur Unix, donc c'est un point discutable.Votre solution ne fonctionne que sur unix +1 – aaronasterling