Jak sprawić, aby python czekał na naciśnięty klawisz?

571

Chcę, aby mój skrypt czekał, aż użytkownik naciśnie dowolny klawisz.

Jak mogę to zrobić?

Janusz
źródło

Odpowiedzi:

543

W Pythonie 3 użyj input():

input("Press Enter to continue...")

W Pythonie 2 użyj raw_input():

raw_input("Press Enter to continue...")

To tylko czeka, aż użytkownik naciśnie klawisz Enter.

Można chcieć użyć msvcrt ((tylko Windows / DOS) Moduł msvcrt daje dostęp do szeregu funkcji w bibliotece Microsoft Visual C / C ++ Runtime Library (MSVCRT)):

import msvcrt as m
def wait():
    m.getch()

To powinno poczekać na naciśnięcie klawisza.

Dodatkowe informacje:

w Pythonie 3 raw_input()nie istnieje

W Python 2 input(prompt)jest równoważne zeval(raw_input(prompt))

riza
źródło
54
Otrzymuję ten błąd, gdy próbuję to zrobić w Pythonie 2.7: „Błąd składni: nieoczekiwany błąd EOF podczas analizowania”
Jon Tirsen,
8
@ Solarsaturn9 i coraz większa ich liczba nie. Tak więc ta odpowiedź nie zadziałała dla mnie i dla wielu innych, którzy tu przychodzą.
ctrl-alt-delor
5
@richard przy użyciu input () powinien również działać na innych platformach. To niedorzeczne, aby zadokować punkty, aby zapewnić alternatywne rozwiązanie tylko dla systemu Windows, gdy pierwsze rozwiązanie jest wieloplatformowe.
Cory Buckley
7
@ Solarsaturn9 przeczytaj pytanie i odpowiedz ponownie: inputnie kontynuuje się po naciśnięciu dowolnego klawisza, tylko po naciśnięciu klawisza enter.
ctrl-alt-delor
13
@JonTirsen to dlatego, że Python 2.7 ma funkcję o nazwie input, która ocenia wprowadzony ciąg. Aby to naprawić, użyj raw_input
Samy Bencherif
316

Jednym ze sposobów na zrobienie tego w Pythonie 2 jest użycie raw_input():

raw_input("Press Enter to continue...")

W python3 jest po prostu input()

Greg Hewgill
źródło
17
A kiedy może to być jeden z wielu kluczy? Nie tylko enter?
noio
33
W Pythonie 3+ zmieniło się to na just input().
palswim
Używając szóstki dla kodu kompatybilnego z Py2 i Py3:from six.moves import input; input("Press Enter to continue...")
rcoup
56

W moim systemie Linux używam następującego kodu. Jest to podobne do kodu, który widziałem gdzie indziej (na przykład w starych pytaniach do Pythona), ale kod ten obraca się w ciasnej pętli, w której ten kod nie działa i jest wiele dziwnych przypadków narożnych, których kod nie uwzględnia tego kod robi.

def read_single_keypress():
    """Waits for a single keypress on stdin.

    This is a silly function to call if you need to do it a lot because it has
    to store stdin's current setup, setup stdin for reading single keystrokes
    then read the single keystroke then revert stdin back after reading the
    keystroke.

    Returns a tuple of characters of the key that was pressed - on Linux, 
    pressing keys like up arrow results in a sequence of characters. Returns 
    ('\x03',) on KeyboardInterrupt which can happen when a signal gets
    handled.

    """
    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    ret = []
    try:
        ret.append(sys.stdin.read(1)) # returns a single character
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save | os.O_NONBLOCK)
        c = sys.stdin.read(1) # returns a single character
        while len(c) > 0:
            ret.append(c)
            c = sys.stdin.read(1)
    except KeyboardInterrupt:
        ret.append('\x03')
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return tuple(ret)
mheyman
źródło
Chociaż jest to moja ulubiona z odpowiedzi tutaj, podobnie jak inni nie łapią takich rzeczy, jak zmiana, kontrola itp.
Mala
1
@Mala, że ​​prawie nie jest możliwe w czystym Pythonie; może powinieneś napisać moduł C?
kot
W moim systemie pojawia się „\ x03” podczas przerwania klawiatury (Ctrl-C).
NRD
1
ctrl-c jest ascii 3, więc należy się tego spodziewać. Jeśli chcesz podnieść sygnał na ctrl-c, łatwym rozwiązaniem jest umieszczenie if ord (wartość_wrócona) == 3: os.kill (os.getpid (), signal.SIGINT), ale możesz również wyłączyć przetwarzanie sygnału przez attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG, i pozbywaj się wyjątku przetwarzania KeyboardInterrupt. Uwaga - Zmieniłem wartość zwracaną dla KeyboardInterrupt na „\ x03” na cześć twojego zapytania (a ponieważ powoduje to, że ten kod zawsze zwraca ciąg znaków).
mheyman
Jak można dostosować powyższy kod, aby zwracał krotkę dla złożonego naciśnięcia klawisza, takiego jak „Page Up” lub „Left Arrow”?
Derek
33

Jeśli nie masz nic przeciwko w zależności od poleceń systemowych, możesz użyć następujących opcji:

Linux:

import os
os.system('read -sn 1 -p "Press any key to continue..."')
print

Windows:

import os
os.system("pause")
CrouZ
źródło
Jeśli chcesz kontynuować bieg, dopóki nie zostanie podniesiony sygnał (jak SIGINT), możesz również sprawdzić wartość zwrotną z, systema następnie zadzwonić sys.exit(0).
James Taylor
29

Po prostu używa

input("Press Enter to continue...")

spowoduje błąd SyntaxError: oczekiwany EOF podczas analizowania.

Proste zastosowanie poprawki:

try:
    input("Press enter to continue")
except SyntaxError:
    pass
wszystko prawda
źródło
5
Nie używaj inputw Pythonie 2 - poprawna funkcja to raw_input. W python 2 inputjest równoważne z eval(raw_input()).
Blorgbeard wyszedł
2
Ignoruje to wszystkie klawisze, które użytkownik naciska, dopóki nie naciśnie Enter, co jest zupełnie inne niż to, o co prosi OP.
Jonathan Hartley,
1
Ponadto, jeśli zamierzasz użyć polecenia „input”, wyłapanie błędu składni nie jest właściwe. Bez względu na to, jaki typ użytkownika zostanie oceniony, więc jeśli na przykład wpisze on „1/0”, wówczas podniesiony zostanie ZeroDivisionError zamiast SyntaxError, a program zakończy działanie.
Jonathan Hartley
Jak wspomniano @Blorgbeard, wystarczy użyć raw_input („Naciśnij Enter, aby kontynuować ...”). Używam go teraz często podczas debugowania.
alltrue
15

Pyton instrukcja przewiduje, co następuje:

import termios, fcntl, sys, os
fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:
    while 1:
        try:
            c = sys.stdin.read(1)
            print "Got character", repr(c)
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

które można umieścić w walizce.

Jaap Versteegh
źródło
12
Dobrą praktyką jest skopiowanie rzeczy, do której się łączysz, aby wiedza pozostała, nawet jeśli link umrze (i tak się stanie!).
Richard
1
Jak mogę to zrobić w Pythonie 3.x? W wersji 3.x, po zmianie instrukcji print na kompatybilną, po prostu zapętla się ona nieskończenie i nie czeka na dane wejściowe. Jednak działa świetnie w Pythonie 2.
kot
Link został zaktualizowany w celu przekierowania na inną stronę. Nowy link jest tutaj.
Matthias
15

Cross Platform, kod Python 2/3:

# import sys, os

def wait_key():
    ''' Wait for a key press on the console and return it. '''
    result = None
    if os.name == 'nt':
        import msvcrt
        result = msvcrt.getch()
    else:
        import termios
        fd = sys.stdin.fileno()

        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)

        try:
            result = sys.stdin.read(1)
        except IOError:
            pass
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

    return result

Usunąłem fctl / nie blokujące rzeczy, ponieważ dawały IOErrors i nie potrzebowałem tego. Używam tego kodu, ponieważ chcę go zablokować. ;)

Uzupełnienie:

Zaimplementowałem to w pakiecie na PyPI z wieloma innymi dodatkami zwanymi konsolami :

>>> from console.utils import wait_key

>>> wait_key()
'h'
Gringo Suave
źródło
1
Wystąpił błąd: niewłaściwy ioctl dla urządzenia ”
Benoit
@Benoit, który system operacyjny?
Gringo Suave
14

Nie znam metody niezależnej od platformy, ale w systemie Windows, jeśli używasz modułu msvcrt, możesz użyć jego funkcji getch:

import msvcrt
c = msvcrt.getch()
print 'you entered', c

mscvcrt zawiera również nieblokującą funkcję kbhit (), aby sprawdzić, czy klawisz został naciśnięty bez czekania (nie jestem pewien, czy istnieje odpowiednia funkcja curses). W systemie UNIX istnieje pakiet curses, ale nie jestem pewien, czy można go użyć bez użycia go dla wszystkich danych wyjściowych ekranu. Ten kod działa w systemie UNIX:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

Zauważ, że curses.getch () zwraca numer porządkowy wciśniętego klawisza, aby uzyskać taki sam wynik, jaki musiałem rzucić.

John Gaines Jr.
źródło
Używanie przekleństw jest o wiele ładniejsze niż dość skomplikowane przykłady opisane w instrukcji, nawet jeśli wiąże się to z ogromną zależnością. +1
Damian
4

Jeśli chcesz poczekać na wejście (aby użytkownik pukający w klawiaturę nie spowodował, że wydarzy się coś nieoczekiwanego) użyj

sys.stdin.readline()
Andrzej Pasztet
źródło
2
Chodzi o to, aby użytkownik nie musiał naciskać tylko klawisza Enter, aby na przykład móc po prostu uderzyć spacją. Jeśli potrzebujesz Enter, aby uniknąć czegoś niezamierzonego, to zły projekt.
Synetech
3

Jestem nowy w Pythonie i już myślałem, że jestem zbyt głupi, aby odtworzyć najprostsze sugestie tutaj przedstawione. Okazuje się, że istnieje pułapka, o której należy wiedzieć:

Kiedy skrypt Pythona jest wykonywany z IDLE, niektóre polecenia IO wydają się zachowywać zupełnie inaczej (ponieważ tak naprawdę nie ma okna terminala).

Na przykład. msvcrt.getch nie blokuje i zawsze zwraca $ ff. Zostało to już zgłoszone dawno temu (patrz np. Https://bugs.python.org/issue9290 ) - i jest oznaczone jako naprawione, jakoś problem wydaje się utrzymywać w aktualnych wersjach python / IDLE.

Więc jeśli którykolwiek z powyższych kodów nie działa, spróbuj uruchomić skrypt ręcznie, a NIE z IDLE .

ralfiii
źródło
0

Jeśli chcesz sprawdzić, czy nacisnęli dokładnie klawisz (np. Powiedz „b”) Zrób to:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break
E40
źródło
8
Wymaga to od użytkownika wpisania „b” (lub czegoś innego), a następnie naciśnięcia enter, co jest zupełnie inne niż to, o co prosi OP.
Jonathan Hartley
0

os.system wydaje się zawsze wywoływać sh, co nie rozpoznaje opcji s i n dla odczytu. Jednak polecenie odczytu można przekazać do bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")
James King
źródło
2
Przeczytana dokumentacja każe mi myśleć, że nie upłynie limit czasu, chyba że podasz opcję -t.
James King