Làm thế nào để tôi làm cho python chờ đợi một phím nhấn?


571

Tôi muốn tập lệnh của mình đợi cho đến khi người dùng nhấn bất kỳ phím nào.

Làm thế nào để làm điều đó?

Câu trả lời:


543

Trong Python 3 sử dụng input():

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

Trong Python 2 sử dụng raw_input():

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

Điều này chỉ chờ người dùng nhấn enter mặc dù.

Người ta có thể muốn sử dụng msvcrt ((chỉ dành cho Windows / DOS) Mô-đun msvcrt cho phép bạn truy cập vào một số chức năng trong Thư viện thời gian chạy Microsoft Visual C / C ++ (MSVCRT)):

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

Điều này sẽ chờ cho một phím nhấn.

Thông tin bổ sung:

trong Python 3 raw_input() không tồn tại

Trong Python 2 input(prompt)tương đương vớieval(raw_input(prompt))


54
Tôi gặp lỗi này khi tôi cố gắng thực hiện điều này trong Python 2.7: "Cú pháp: EOF bất ngờ khi phân tích cú pháp"
Jon Tirsen

8
@ Solarsaturn9 và một số lượng lớn và ngày càng không. Do đó, câu trả lời này không có tác dụng với tôi và nhiều người khác đến đây.
ctrl-alt-delor

5
@richard sử dụng input () cũng sẽ hoạt động trên các nền tảng khác. Thật nực cười khi đưa ra các điểm để cung cấp giải pháp thay thế duy nhất cho Windows khi giải pháp đầu tiên là đa nền tảng.
Cory Buckley

7
@ Solarsaturn9 đọc câu hỏi và trả lời lại: inputkhông tiếp tục nếu nhấn bất kỳ phím nào, chỉ khi nhấn phím Enter.
ctrl-alt-delor

13
@JonTirsen đó là vì Python 2.7 có một hàm gọi là đầu vào để đánh giá chuỗi bạn nhập. Để khắc phục, hãy sử dụng raw_input
Samy Bencherif

316

Một cách để làm điều này trong Python 2, là sử dụng raw_input():

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

Trong python3, nó chỉ input()


17
Thế còn khi nó có thể là một trong một số phím? Không chỉ enter?
noio

33
Với Python 3+ , điều này đã thay đổi thành chỉ input().
palswim

Sử dụng sáu cho mã tương thích Py2 & Py3:from six.moves import input; input("Press Enter to continue...")
RCoup

56

Trên hộp linux của tôi, tôi sử dụng mã sau đây. Mã này tương tự như mã tôi đã thấy ở nơi khác (ví dụ: trong Câu hỏi thường gặp về python cũ) nhưng mã đó quay vòng trong một vòng lặp chặt chẽ trong đó mã này không có và có rất nhiều trường hợp góc kỳ lạ mà mã không giải thích cho điều này mã nào.

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)

Mặc dù đây là câu trả lời yêu thích của tôi ở đây, giống như những câu trả lời khác không bắt được những thứ như thay đổi, kiểm soát, v.v.
Mala

1
@Mala điều đó không thể thực hiện được trong Python thuần túy; có lẽ bạn nên viết một mô-đun C?
mèo

Tôi đang nhận được "\ x03" khi ngắt bàn phím (Ctrl-C) trên hệ thống của mình.
GDR

1
ctrl-c là một ascii 3 vì vậy đó là mong đợi. Nếu bạn muốn tăng tín hiệu trên ctrl-c, giải pháp dễ dàng là đặt if ord (return_value) == 3: os.kill (os.getpid (), signal.SIGINT) nhưng bạn cũng có thể tắt xử lý tín hiệu bởi attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG và thoát khỏi việc xử lý ngoại trừ KeyboardInterrupt. Lưu ý - Tôi đã thay đổi giá trị trả về cho KeyboardInterrupt thành '\ x03' để vinh danh truy vấn của bạn (và vì điều đó làm cho mã này luôn trả về một chuỗi).
mheyman

Làm thế nào mã trên có thể được điều chỉnh để nó trả về một tuple cho một phím bấm phức tạp như "Page Up" hoặc "Mũi tên trái"?
Derek

33

Nếu bạn ổn với tùy thuộc vào lệnh hệ thống, bạn có thể sử dụng như sau:

Linux:

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

Các cửa sổ:

import os
os.system("pause")

Nếu bạn muốn tiếp tục chạy cho đến khi tín hiệu được tăng (như SIGINT), bạn cũng có thể kiểm tra giá trị trả về từ systemđó và sau đó gọi sys.exit(0).
James Taylor

29

Đơn giản chỉ cần sử dụng

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

sẽ gây ra SyntaxError: EOF dự kiến ​​trong khi phân tích cú pháp.

Sử dụng sửa chữa đơn giản:

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

5
Không sử dụng inputtrong python 2 - chức năng chính xác là raw_input. Trong python 2, inputtương đương với eval(raw_input()).
Blorgbeard sẽ ra vào

2
Điều này bỏ qua tất cả các phím mà người dùng nhấn, cho đến khi họ nhấn enter, điều này hoàn toàn khác với những gì OP đang yêu cầu.
Jonathan Hartley

1
Ngoài ra, nếu bạn định sử dụng 'đầu vào', việc bắt SyntaxError là không phù hợp. Dù loại người dùng được đánh giá là gì, vì vậy, ví dụ, nếu họ gõ "1/0" thì ZeroDivisionError được nâng lên thay vì SyntaxError và chương trình của bạn sẽ thoát.
Jonathan Hartley

Như @Blorgbeard đã đề cập, chỉ cần sử dụng raw_input ("Nhấn Enter để tiếp tục ...") là đủ. Tôi sử dụng nó thường xuyên bây giờ khi gỡ lỗi.
tất cả các

15

Hướng dẫn python cung cấp như sau:

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)

có thể được đưa vào trường hợp sử dụng của bạn.


12
Đó là một thực hành tốt để sao chép thứ bạn đang liên kết để kiến ​​thức vẫn còn, ngay cả khi liên kết bị chết (và họ làm được!).
Richard

1
Làm cách nào tôi có thể thực hiện công việc này trong Python 3.x? Trong 3.x, sau khi thay đổi câu lệnh in thành tương thích, điều này chỉ lặp lại vô hạn và không chờ đầu vào. Nó hoạt động rất tốt trong Python 2, mặc dù.
mèo

Liên kết đã được cập nhật để chuyển hướng đến một trang khác. Các liên kết mới là ở đây.
Matthias

15

Nền tảng chéo, mã 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

Tôi đã xóa các thứ fctl / không chặn bởi vì nó đang cho IOError s và tôi không cần nó. Tôi đang sử dụng mã này đặc biệt bởi vì tôi muốn nó bị chặn. ;)

Phụ lục:

Tôi đã thực hiện điều này trong một gói trên PyPI với rất nhiều tính năng khác được gọi là console :

>>> from console.utils import wait_key

>>> wait_key()
'h'

1
Tôi đã gặp lỗi: ioctl không phù hợp cho thiết bị '
Benoit

@Benoit HĐH nào?
Gringo Suave

Linux - Ubuntu 20.04
Benoit

14

Tôi không biết về cách thức hoạt động độc lập với nền tảng, nhưng trong Windows, nếu bạn sử dụng mô-đun msvcrt, bạn có thể sử dụng chức năng getch của nó:

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

mscvcrt cũng bao gồm hàm kbhit () không chặn để xem nếu một phím được nhấn mà không cần chờ đợi (không chắc có chức năng nguyền rủa tương ứng không). Trong UNIX, có gói lời nguyền, nhưng không chắc bạn có thể sử dụng nó mà không sử dụng nó cho tất cả đầu ra màn hình hay không. Mã này hoạt động theo UNIX:

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

Lưu ý rằng curses.getch () trả về số thứ tự của phím được nhấn để làm cho nó có cùng một đầu ra tôi phải bỏ nó.


Sử dụng lời nguyền sẽ đẹp hơn rất nhiều so với các ví dụ khá phức tạp được mô tả trong sách hướng dẫn, ngay cả khi nó liên quan đến một sự phụ thuộc rất lớn. +1
Damian

4

Nếu bạn muốn đợi nhập (để người dùng gõ bàn phím không gây ra sự cố ngoài ý muốn), hãy sử dụng

sys.stdin.readline()

2
Toàn bộ vấn đề là người dùng không phải chỉ nhấn phím Enter, ví dụ như có thể chỉ cần tát phím cách. Nếu bạn yêu cầu Enter để tránh điều gì đó ngoài ý muốn xảy ra, thì đó là thiết kế tồi.
Synetech

3

Tôi chưa quen với python và tôi đã nghĩ rằng mình quá ngu ngốc khi sao chép những gợi ý đơn giản nhất được đưa ra ở đây. Hóa ra, có một cạm bẫy người ta nên biết:

Khi tập lệnh python được thực thi từ IDLE, một số lệnh IO dường như hoạt động hoàn toàn khác (vì thực tế không có cửa sổ đầu cuối).

Ví dụ. msvcrt.getch không chặn và luôn trả về $ ff. Điều này đã được báo cáo từ lâu (xem ví dụ: https://bugs.python.org/su9290 ) - và nó được đánh dấu là đã sửa, bằng cách nào đó, vấn đề dường như vẫn tồn tại trong các phiên bản hiện tại của python / IDLE.

Vì vậy, nếu bất kỳ mã nào được đăng ở trên không phù hợp với bạn, hãy thử chạy tập lệnh theo cách thủ công và KHÔNG từ IDLE .


0

Nếu bạn muốn xem liệu họ có nhấn một phím chính xác không (như nói 'b') Thực hiện việc này:

while True:
    choice = raw_input("> ")

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

8
Điều này yêu cầu người dùng nhập 'b' (hoặc một cái gì đó khác) sau đó nhấn enter, điều này hoàn toàn khác với những gì OP đang yêu cầu.
Jonathan Hartley

0

os.system dường như luôn gọi sh, không nhận ra các tùy chọn s và n để đọc. Tuy nhiên, lệnh đọc có thể được truyền cho bash:

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

2
Tài liệu đọc khiến tôi nghĩ rằng nó sẽ không hết thời gian trừ khi bạn chỉ định tùy chọn -t.
James King
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.