Wie lasse ich Python auf eine gedrückte Taste warten?

571

Ich möchte, dass mein Skript wartet, bis der Benutzer eine beliebige Taste drückt.

Wie mache ich das?

Janusz
quelle

Antworten:

543

Verwenden Sie in Python 3input() :

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

In Python 2 verwenden Sie raw_input():

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

Dies wartet jedoch nur darauf, dass der Benutzer die Eingabetaste drückt.

Möglicherweise möchten Sie msvcrt verwenden ((nur Windows / DOS). Das msvcrt- Modul bietet Ihnen Zugriff auf eine Reihe von Funktionen in der Microsoft Visual C / C ++ - Laufzeitbibliothek (MSVCRT)):

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

Dies sollte auf einen Tastendruck warten.

Zusätzliche Information:

in Python 3 raw_input()existiert nicht

In Python ist 2 input(prompt)gleichbedeutend miteval(raw_input(prompt))

Riza
quelle
54
Ich erhalte diesen Fehler, wenn ich versuche, dies in Python 2.7 zu tun: "SyntaxError: unerwartete EOF beim Parsen"
Jon Tirsen
8
@ Solarsaturn9 und eine zunehmende und große Anzahl nicht. Daher hat diese Antwort für mich und die vielen anderen, die hierher kommen, nicht funktioniert.
Strg-Alt-Delor
5
@richard mit input () sollte auch auf anderen Plattformen funktionieren. Es ist lächerlich, Punkte anzudocken, um eine alternative Windows-Lösung bereitzustellen, wenn die erste Lösung plattformübergreifend ist.
Cory Buckley
7
@ Solarsaturn9 Lesen Sie die Frage und antworten Sie erneut: Fährt inputnicht fort, wenn eine Taste gedrückt wird, sondern nur, wenn die Eingabetaste gedrückt wird.
Strg-Alt-Delor
13
@ JonTirsen, weil Python 2.7 eine Funktion namens input hat, die die eingegebene Zeichenfolge auswertet. Verwenden Sie zur Behebung raw_input
Samy Bencherif
316

Eine Möglichkeit, dies in Python 2 zu tun, besteht darin, Folgendes zu verwenden raw_input():

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

In Python3 ist es nur input()

Greg Hewgill
quelle
17
Was ist, wenn es einer von mehreren Schlüsseln sein kann? Nicht nur enter?
Noio
33
Mit Python 3+ hat sich dies auf just geändert input().
Palswim
Verwenden von sechs für Py2 & Py3-kompatiblen Code:from six.moves import input; input("Press Enter to continue...")
rcoup
56

Auf meiner Linux-Box verwende ich den folgenden Code. Dies ähnelt dem Code, den ich an anderer Stelle gesehen habe (zum Beispiel in den alten Python-FAQs), aber dieser Code dreht sich in einer engen Schleife, in der dieser Code dies nicht tut, und es gibt viele seltsame Eckfälle, in denen der Code dies nicht berücksichtigt Code tut.

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
quelle
Dies ist zwar mein Favorit unter den Antworten hier, aber die anderen fangen Dinge wie Verschiebung, Kontrolle usw. nicht ein
Mala
1
@ Mala, dass in reinem Python so ziemlich nichts möglich ist; Vielleicht sollten Sie ein C-Modul schreiben?
Katze
Ich erhalte "\ x03" bei Tastaturinterrupt (Strg-C) auf meinem System.
DDR
1
Strg-C ist ein ASCII 3, so dass dies erwartet wird. Wenn Sie ein Signal auf Strg-C auslösen möchten, besteht die einfache Lösung darin, ein if ord (return_value) == 3: os.kill (os.getpid (), signal.SIGINT) einzugeben. Sie können jedoch auch die Signalverarbeitung deaktivieren durch attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG, und entfernen Sie die Ausnahme-KeyboardInterrupt-Verarbeitung. Hinweis - Ich habe den Rückgabewert für KeyboardInterrupt zu Ehren Ihrer Abfrage in '\ x03' geändert (und weil dieser Code dadurch immer eine Zeichenfolge zurückgibt ).
Mheyman
Wie könnte der obige Code so angepasst werden, dass er ein Tupel für einen komplexen Tastendruck wie "Bild auf" oder "Pfeil nach links" zurückgibt?
Derek
33

Wenn Sie mit den Systembefehlen einverstanden sind, können Sie Folgendes verwenden:

Linux:

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

Windows:

import os
os.system("pause")
CrouZ
quelle
Wenn Sie so lange laufen möchten, bis ein Signal ausgelöst wird (wie bei SIGINT), können Sie auch den Rückgabewert von überprüfen systemund dann aufrufen sys.exit(0).
James Taylor
29

Einfach benutzen

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

verursacht einen SyntaxError: erwartete EOF beim Parsen.

Einfache Fixverwendung:

try:
    input("Press enter to continue")
except SyntaxError:
    pass
alles wahr
quelle
5
Nicht inputin Python 2 verwenden - die richtige Funktion ist raw_input. In Python 2 inputist äquivalent zu eval(raw_input()).
Blorgbeard ist
2
Dadurch werden alle Tasten ignoriert, die der Benutzer drückt, bis er die Eingabetaste drückt. Dies unterscheidet sich erheblich von den Anforderungen des OP.
Jonathan Hartley
1
Wenn Sie 'input' verwenden möchten, ist es nicht angemessen, einen SyntaxError abzufangen. Unabhängig davon, welche Benutzertypen ausgewertet werden. Wenn sie beispielsweise "1/0" eingeben, wird anstelle eines SyntaxError ein ZeroDivisionError ausgelöst und Ihr Programm wird beendet.
Jonathan Hartley
Wie @Blorgbeard bereits erwähnt hat, reicht es aus, nur raw_input zu verwenden ("Drücken Sie die Eingabetaste, um fortzufahren ..."). Ich benutze es jetzt oft beim Debuggen.
Alltrue
15

Das Python- Handbuch enthält Folgendes:

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)

welches in Ihren Anwendungsfall gerollt werden kann.

Jaap Versteegh
quelle
12
Es ist empfehlenswert, das zu kopierende Objekt so zu kopieren, dass das Wissen erhalten bleibt, auch wenn der Link stirbt (und das tun sie auch!).
Richard
1
Wie kann ich diese Funktion in Python 3.x ausführen? In 3.x wird nach dem Ändern der print-Anweisung als kompatibel nur eine Endlosschleife ausgeführt, die nicht auf Eingaben wartet. In Python 2 funktioniert es jedoch hervorragend.
Katze
Der Link wurde aktualisiert, um auf eine andere Seite umzuleiten. Der neue Link ist hier.
Matthias
15

Plattformübergreifender Python 2/3 Code:

# 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

Ich habe das fctl / nicht blockierende Zeug entfernt, weil es IOErrors gab und ich es nicht brauchte. Ich verwende diesen Code speziell, weil ich möchte, dass er blockiert wird. ;)

Nachtrag:

Ich habe dies in einem Paket auf PyPI mit vielen anderen Extras namens Konsole implementiert :

>>> from console.utils import wait_key

>>> wait_key()
'h'
Gringo Suave
quelle
1
Ich habe eine Fehlermeldung erhalten: Unangemessenes ioctl für Gerät '
Benoit
@ Benoit welches Betriebssystem?
Gringo Suave
Linux - Ubuntu 20.04
Benoit
14

Ich kenne keine plattformunabhängige Methode, aber unter Windows können Sie, wenn Sie das msvcrt-Modul verwenden, dessen getch-Funktion verwenden:

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

mscvcrt enthält auch die nicht blockierende Funktion kbhit (), um festzustellen, ob eine Taste gedrückt wurde, ohne zu warten (nicht sicher, ob es eine entsprechende Fluchfunktion gibt). Unter UNIX gibt es das Curses-Paket, aber Sie sind sich nicht sicher, ob Sie es verwenden können, ohne es für die gesamte Bildschirmausgabe zu verwenden. Dieser Code funktioniert unter UNIX:

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

Beachten Sie, dass curses.getch () die Ordnungszahl der gedrückten Taste zurückgibt, damit sie dieselbe Ausgabe hat, die ich zum Umwandeln hatte.

John Gaines Jr.
quelle
Die Verwendung von Flüchen ist viel schöner als die im Handbuch beschriebenen verworrenen Beispiele, auch wenn sie eine große Abhängigkeit beinhalten. +1
Damian
4

Wenn Sie auf die Eingabe warten möchten (damit der Benutzer, der auf die Tastatur klopft, nicht dazu führt, dass etwas Unbestimmtes passiert), verwenden Sie

sys.stdin.readline()
Andrew Pate
quelle
2
Der springende Punkt ist, dass der Benutzer nicht nur die Eingabetaste drücken muss, um beispielsweise nur die Leertaste drücken zu können. Wenn Sie Enter benötigen, um zu verhindern, dass etwas Unbeabsichtigtes passiert, ist das schlechtes Design.
Synetech
3

Ich bin neu in Python und dachte bereits, ich sei zu dumm, um die einfachsten Vorschläge zu reproduzieren, die hier gemacht wurden. Es stellt sich heraus, dass es eine Falle gibt, die man kennen sollte:

Wenn ein Python-Skript von IDLE ausgeführt wird, scheinen sich einige E / A-Befehle völlig anders zu verhalten (da es tatsächlich kein Terminalfenster gibt).

Z.B. msvcrt.getch ist nicht blockierend und gibt immer $ ff zurück. Dies wurde bereits vor langer Zeit gemeldet (siehe z. B. https://bugs.python.org/issue9290 ) - und es wurde als behoben markiert. Irgendwie scheint das Problem in aktuellen Versionen von Python / IDLE weiterhin zu bestehen.

Wenn einer der oben genannten Codes für Sie nicht funktioniert, führen Sie das Skript manuell und NICHT über IDLE aus .

ralfiii
quelle
0

Wenn Sie sehen möchten, ob sie eine genaue Taste gedrückt haben (z. B. 'b'), gehen Sie folgendermaßen vor:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break
E40
quelle
8
Dies erfordert, dass der Benutzer 'b' (oder etwas anderes) eingibt und dann die Eingabetaste drückt, was sich stark von dem unterscheidet, was das OP verlangt.
Jonathan Hartley
0

os.system scheint immer sh aufzurufen, das die Optionen s und n zum Lesen nicht erkennt. Der Lesebefehl kann jedoch an bash übergeben werden:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")
James King
quelle
2
Die gelesene Dokumentation lässt mich denken, dass es keine Zeitüberschreitung gibt, wenn Sie nicht die Option -t angeben.
James King