如何读取键盘输入?

135

我想在Python中从键盘读取数据。 我尝试了这段代码:

nb = input('Choose a number')
print('Number%s \n' % (nb))

但它无法运行,无论是在Eclipse还是终端中,总是在问题处停止。我可以输入一个数字,但之后什么都不会发生。

你知道为什么吗?


17
我很确定原帖作者只是在输入数字后忘了按回车键,而且没有一个回答实际上回答了这个问题。 - Aran-Fey
你是要获取键盘按下事件还是仅仅让用户输入一些内容? - Simon Champney
5个回答

136

使用

input('Enter your input:')

如果您使用的是Python 3。

如果您想要一个数值,只需进行转换:

try:
    mode = int(input('Input:'))
except ValueError:
    print("Not a number")
如果您使用的是Python 2,则需要使用raw_input而不是input

2
非阻塞多线程版本,这样您就可以继续做其他事情,而不是在键盘输入上阻塞:https://dev59.com/UW035IYBdhLWcg3weP3f#53344690 - Gabriel Staples

87

看起来你在混合使用两种不同版本的Python(Python 2.x和Python 3.x)……基本上这是正确的:

nb = input('Choose a number: ')

问题在于它只支持Python 3。如@sharpner所回答的那样,对于旧版本的Python(2.x),您必须使用raw_input函数:

nb = raw_input('Choose a number: ')

如果你想将其转换为数字,那么你应该尝试:

number = int(nb)

...但需要注意这可能会引发异常:

try:
    number = int(nb)
except ValueError:
    print("Invalid number")

如果你想使用格式化输出数字,在Python 3中建议使用str.format()

print("Number: {0}\n".format(number))

改为:

print('Number %s \n' % (nb))

但是在Python 2.7和Python 3中,str.format()%两种选项都可以使用。


2
如果需要友好的用户输入体验,始终在字符串后面加上一个空格,例如:Enter Tel: 12340404,而不是 Enter Tel12340404。注意空格的重要性。 :P - Mehrad
完成。感谢您的建议。 - Baltasarq

35
非阻塞、多线程示例:
由于键盘输入会阻塞(因为input()函数会阻塞),这通常不是我们想要的(我们经常希望继续做其他事情),因此这是一个非常简化的多线程示例,演示了如何在主应用程序运行的同时,仍然能够读取键盘输入。我在我的eRCaGuy_PyTerm串行终端程序这里(在代码中搜索input())中使用了这种技术。
这个示例通过创建一个后台线程,不断调用input()函数,并将接收到的任何数据传递给一个队列来实现。
这样,您的主线程可以自由地做任何想做的事情,只要队列中有数据,就可以从第一个线程接收键盘输入数据。
1. 纯Python 3代码示例(无注释):
import threading
import queue
import time

def read_kbd_input(inputQueue):
    print('Ready for keyboard input:')
    while (True):
        input_str = input()
        inputQueue.put(input_str)

def main():
    EXIT_COMMAND = "exit"
    inputQueue = queue.Queue()

    inputThread = threading.Thread(target=read_kbd_input, args=(inputQueue,), daemon=True)
    inputThread.start()

    while (True):
        if (inputQueue.qsize() > 0):
            input_str = inputQueue.get()
            print("input_str = {}".format(input_str))

            if (input_str == EXIT_COMMAND):
                print("Exiting serial terminal.")
                break
            
            # Insert your code here to do whatever you want with the input_str.

        # The rest of your program goes here.

        time.sleep(0.01) 
    print("End.")

if (__name__ == '__main__'): 
    main()

2. 与上述相同的Python 3代码,但附有详细的解释性注释:

"""
read_keyboard_input.py

Gabriel Staples
www.ElectricRCAircraftGuy.com
14 Nov. 2018

References:
- https://pyserial.readthedocs.io/en/latest/pyserial_api.html
- *****https://www.tutorialspoint.com/python/python_multithreading.htm
- *****https://en.wikibooks.org/wiki/Python_Programming/Threading
- https://dev59.com/iXI-5IYBdhLWcg3w8NOB
- https://docs.python.org/3/library/queue.html
- https://docs.python.org/3.7/library/threading.html

To install PySerial: `sudo python3 -m pip install pyserial`

To run this program: `python3 this_filename.py`

"""

import threading
import queue
import time

def read_kbd_input(inputQueue):
    print('Ready for keyboard input:')
    while (True):
        # Receive keyboard input from user.
        input_str = input()
        
        # Enqueue this input string.
        # Note: Lock not required here since we are only calling a single Queue method, not a sequence of them 
        # which would otherwise need to be treated as one atomic operation.
        inputQueue.put(input_str)

def main():

    EXIT_COMMAND = "exit" # Command to exit this program

    # The following threading lock is required only if you need to enforce atomic access to a chunk of multiple queue
    # method calls in a row.  Use this if you have such a need, as follows:
    # 1. Pass queueLock as an input parameter to whichever function requires it.
    # 2. Call queueLock.acquire() to obtain the lock.
    # 3. Do your series of queue calls which need to be treated as one big atomic operation, such as calling
    # inputQueue.qsize(), followed by inputQueue.put(), for example.
    # 4. Call queueLock.release() to release the lock.
    # queueLock = threading.Lock() 

    #Keyboard input queue to pass data from the thread reading the keyboard inputs to the main thread.
    inputQueue = queue.Queue()

    # Create & start a thread to read keyboard inputs.
    # Set daemon to True to auto-kill this thread when all other non-daemonic threads are exited. This is desired since
    # this thread has no cleanup to do, which would otherwise require a more graceful approach to clean up then exit.
    inputThread = threading.Thread(target=read_kbd_input, args=(inputQueue,), daemon=True)
    inputThread.start()

    # Main loop
    while (True):

        # Read keyboard inputs
        # Note: if this queue were being read in multiple places we would need to use the queueLock above to ensure
        # multi-method-call atomic access. Since this is the only place we are removing from the queue, however, in this
        # example program, no locks are required.
        if (inputQueue.qsize() > 0):
            input_str = inputQueue.get()
            print("input_str = {}".format(input_str))

            if (input_str == EXIT_COMMAND):
                print("Exiting serial terminal.")
                break # exit the while loop
            
            # Insert your code here to do whatever you want with the input_str.

        # The rest of your program goes here.

        # Sleep for a short time to prevent this thread from sucking up all of your CPU resources on your PC.
        time.sleep(0.01) 
    
    print("End.")

# If you run this Python file directly (ex: via `python3 this_filename.py`), do the following:
if (__name__ == '__main__'): 
    main()

示例输出:

$ python3 read_keyboard_input.py
准备接收键盘输入:

输入字符串 = 嘿
你好
输入字符串 = 你好
7000
输入字符串 = 7000
退出
输入字符串 = 退出
退出串口终端。
结束。

Python的Queue库是线程安全的:

请注意,Queue.put()Queue.get()以及其他Queue类方法都是线程安全的!(这与C++标准模板库中的队列和其他容器不同!)由于Python的Queue类及其方法是线程安全的,这意味着它们实现了所有内部锁定语义,以便进行线程间操作,因此队列类中的每个函数调用都可以视为单个原子操作。请参阅文档顶部的注释:https://docs.python.org/3/library/queue.html(已加重):

队列模块实现了多生产者、多消费者队列。在多线程编程中,当需要在多个线程之间安全地交换信息时,它尤其有用。该模块中的队列类实现了所有必需的锁定语义。
参考资料:
  1. https://pyserial.readthedocs.io/en/latest/pyserial_api.html
  2. *****https://www.tutorialspoint.com/python/python_multithreading.htm
  3. *****https://en.wikibooks.org/wiki/Python_Programming/Threading
  4. Python: How do I make a subclass from a superclass?
  5. https://docs.python.org/3/library/queue.html
  6. https://docs.python.org/3.7/library/threading.html
  7. [My repo where I use the techniques and code presented above] https://github.com/ElectricRCAircraftGuy/eRCaGuy_PyTerm

相关/交叉链接:

  1. [我的答案] PySerial非阻塞读取循环

@Tim,我认为你提出的修改太过激烈,让这篇文章看起来更像是你的,而不是我的。因此我拒绝了它们。当对别人的帖子进行编辑时,最好着重于更正错误的内容、改善格式或语法,或修正拼写。不应该进行大规模的代码编辑或完全重写答案。如果您想要改变这么多,最好写自己的答案。这里有一个例子:https://dev59.com/m2sz5IYBdhLWcg3w5MA0#38809894。我完全重写了他的代码。只需确保引用来源,并给予应有的功劳。 - Gabriel Staples
我感谢原始答案,@Gabriel。它对我很有帮助。谢谢! :)我的希望是通过许多小的更改来使pylint满意,调整格式和语法,并删除未使用的pyserial引用(具有讽刺意味的是,这就是我找到这个答案的原因),从而实现欢迎的清理。我很失望这不是情况,并谦卑地道歉。我已经修改了代码,但SO似乎没有保留“建议”的编辑。我不会发布此答案的副本/更新,但请随意将任何更改直接作为您自己的更改。干杯! - Tim

0

我来这里是为了寻找如何读取单个字符。

我发现了readchar库,基于这个问题的答案。在pip安装后:

import readchar

key = readchar.readkey()

虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅链接的答案可能会失效。- 来自审查 - Paul Brennan
1
感谢您的详细评论。我发现使用库非常有帮助,想在这里留下这些信息。对我来说,“如何读取字符?”的答案是“使用readchar库”。我添加了一个使用该库的代码示例。 - dfrankow

-1

你可以通过使用变量来简单地使用input()函数。快速示例!

user = input("Enter any text: ")
print(user)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接