Як змусити пітона чекати натиснуту клавішу?


571

Я хочу, щоб мій сценарій зачекав, поки користувач не натисне якусь клавішу.

Як це зробити?

Відповіді:


543

У Python 3 використовуйте input():

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

У Python 2 використовуйте raw_input():

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

Це чекає, поки користувач натисне клавішу enter.

Можливо, захочеться використовувати msvcrt ((лише для Windows / DOS) Модуль msvcrt надає вам доступ до ряду функцій у бібліотеці виконання Microsoft Visual C / C ++ (MSVCRT)):

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

Це повинно чекати натискання клавіші.

Додаткова інформація:

в Python 3 raw_input()не існує

У Python 2 input(prompt)еквівалентноeval(raw_input(prompt))


54
Я отримую цю помилку, коли намагаюся зробити це в Python 2.7: "SyntaxError: несподіваний EOF під час розбору"
— Джон Тірсен

8
@ Solarsaturn9 і зростаюча і велика кількість цього не роблять. Таким чином ця відповідь не спрацювала для мене, а також багатьох інших, які приходять сюди.
— ctrl-alt-delor

5
@richard, що використовує input (), повинен працювати і на інших платформах. Смішно балувати точки для надання альтернативного рішення лише для Windows, коли перше рішення є багатоплатформним.
— Кори Баклі

7
@ Solarsaturn9 прочитайте питання та відповідь ще раз: inputне продовжується, якщо натиснута будь-яка клавіша, лише якщо натиснута клавіша Enter.
— ctrl-alt-delor

13
@JonTirsen тому, що Python 2.7 має функцію, що називається input, яка оцінює введений рядок. Для виправлення використовуйте raw_input
— Samy Bencherif

316

Один із способів зробити це в Python 2 - це використовувати raw_input():

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

У python3 це просто input()


17
А як бути, коли це може бути один із ряду клавіш? Не просто enter?
— noio

33
З Python 3+ це змінилося на справедливе input().
— palswim

Використання шести для сумісного з Py2 та Py3 коду:from six.moves import input; input("Press Enter to continue...")
— rcoup

56

У своєму вікні linux я використовую наступний код. Це схоже на код, який я бачив в іншому місці (наприклад, у старих поширених питаннях python), але цей код закручується в тісному циклі, де цього коду немає, і є безліч непарних кутових справ, коди не враховують це код робить.

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)

Хоча це моя улюблена відповідь тут, як і інші, не вловлюють такі речі, як зсув, контроль тощо
— Мала

1
@Mala, що майже не можливо в чистому Python; можливо, ви повинні написати модуль С?
— кіт

Я отримую "\ x03" на перериванні клавіатури (Ctrl-C) у своїй системі.
— НДР

1
ctrl-c - це ascii 3, так що очікується. Якщо ви хочете підняти сигнал на ctrl-c, найпростішим рішенням є встановлення if (return_value) == 3: os.kill (os.getpid (), signal.SIGINT), але ви також можете вимкнути обробку сигналів by attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG, і позбутися за винятком обробки KeyboardInterrupt. Примітка. Я змінив значення повернення для KeyboardInterrupt на '\ x03' на честь вашого запиту (і тому, що цей код завжди повертає рядок).
— mheyman

Як можна було скорегувати вищезазначений код, щоб він повернув кортеж для складного натискання клавіш, наприклад "Page Up" або "Streft Left"?
— Дерек

33

Якщо у вас все в порядку, залежно від системних команд, ви можете використовувати наступне:

Linux:

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

Windows:

import os
os.system("pause")

Якщо ви хочете продовжувати працювати, поки сигнал не буде піднятий (як-от SIGINT), ви також можете перевірити значення повернення systemта подзвонити sys.exit(0).
— Джеймс Тейлор

29

Просто за допомогою

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

викличе SyntaxError: очікуваний EOF під час розбору.

Просте використання виправлення:

try:
    input("Press enter to continue")
except SyntaxError:
    pass

5
Не використовуйте inputв python 2 - правильна функція raw_input. У python 2 inputеквівалентно eval(raw_input()).
— Blorgbeard вийшов

2
При цьому ігноруються всі клавіші, які користувач натискає, поки вони не натискають клавішу "Введення", що зовсім відрізняється від того, що задає ОП.
— Джонатан Хартлі

1
Крім того, якщо ви збиралися використовувати "введення", ловити SyntaxError не підходить. Які б типи користувачів не оцінювали, тому, наприклад, якщо вони вводять "1/0", тоді ZeroDivisionError піднімається замість SyntaxError, і ваша програма вийде.
— Джонатан Хартлі

Як зазначав @Blorgbeard, просто використовувати raw_input ("Натисніть Enter, щоб продовжити ...") буде достатньо. Я використовую його часто зараз під час налагодження.
— alltrue

15

Пітон керівництво містить наступне:

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)

які можна передати у вашу справу використання.


12
Добре практика копіювати те, з чим ви посилаєтесь, щоб знання залишалися, навіть якщо посилання вмирає (і вони роблять!).
— Річард

1
Як я можу зробити цю роботу в Python 3.x? У 3.x, після зміни заяви на друк на сумісну, вона просто циклічно нескінченна і не чекає введення. Хоча це чудово працює і в Python 2.
— кіт

Посилання було оновлено для перенаправлення на іншу сторінку. Нове посилання тут.
— Маттіас

15

Крос-платформа, код 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

Я видалив матеріал fctl / unblocking, оскільки він давав IOErrors, і мені це не потрібно. Я використовую цей код спеціально, тому що я хочу його блокувати. ;)

Додаток:

Я реалізував це в пакеті на PyPI з великою кількістю інших смаколиків під назвою консоль :

>>> from console.utils import wait_key

>>> wait_key()
'h'

1
Я отримав помилку: Невідповідний ioctl для пристрою '
— Бенуа,

@Benoit, яка ОС?
— Gringo Suave

Linux - Ubuntu 20.04
— Бенуа

14

Я не знаю, як це залежить від платформи, але в Windows, якщо ви використовуєте модуль msvcrt, ви можете використовувати його функцію getch:

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

mscvcrt також включає в себе функцію kbhit (), що не блокує, щоб перевірити, чи була натиснута клавіша без очікування (не впевнений, чи є відповідна функція curses). У UNIX є пакет прокльонів, але не впевнений, чи зможете ви використовувати його, не використовуючи його на весь вихідний екран. Цей код працює під UNIX:

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

Зауважте, що curses.getch () повертає порядковий рядок натиснутої клавіші так, щоб вона мала той самий вихід, який я повинен був надати.


Використовувати прокльони набагато приємніше, ніж досить суперечливі приклади, описані в посібнику, навіть якщо це передбачає величезну залежність. +1
— Даміан

4

Якщо ви хочете зачекати на введення (щоб користувач, який стукає клавіатурою, не спричинив щось непередбачене), використовуйте

sys.stdin.readline()

2
Вся справа в тому, що користувачеві не потрібно натискати лише клавішу Enter, щоб, наприклад, можна було просто ляпнути пробіл. Якщо вам потрібен Enter, щоб уникнути чогось ненавмисного, це поганий дизайн.
— Synetech

3

Я новачок у python, і я вже думав, що я занадто дурний, щоб відтворити найпростіші пропозиції, зроблені тут. Виявляється, тут є підводний камінь, який слід знати:

Коли python-скрипт виконується з IDLE, деякі IO-команди, схоже, поводяться зовсім інакше (оскільки насправді немає вікна терміналу).

Напр. msvcrt.getch не блокує і завжди повертає $ ff. Про це вже давно повідомляється (див., Наприклад, https://bugs.python.org/issue9290 ) - і це позначено як виправлене, певна проблема, здається, зберігається в поточних версіях python / IDLE.

Отже, якщо який-небудь з опублікованих вище кодів не працює для вас, спробуйте запустити скрипт вручну, а НЕ з IDLE .


0

Якщо ви хочете дізнатися, чи натиснули вони точну клавішу (наприклад, сказати "b"), зробіть це:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break

8
Це вимагає, щоб користувач вводив 'b' (або щось інше), а потім натискав клавішу Enter, що зовсім відрізняється від того, про що вимагає ОП.
— Джонатан Хартлі

0

OS.system, здається, завжди викликає sh, який не розпізнає параметри s та n для читання. Однак команда читання може бути передана в bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")

2
Прочитана документація змушує мене думати, що вона не закінчиться, якщо не вказати параметр -t.
— Джеймс Кінг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.