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


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.