在Python中等待输入时,将内容打印到控制台

3

我有一个Python脚本(作为命令行界面),它使用input函数等待输入查询。

while True:
  query = input('Enter query: ')
  thread = Thread(target=exec_query, args=(query,))
  thread.start()

同时,一个工作线程正在执行这些查询。使用 print 函数将查询的输出打印到命令行。
def exec_query(query_data):
  # doing a complex data processing ...
  print('results of the query')

因此,print函数的输出被写在主线程第二次执行print函数时打印的前缀'Enter query: '之后。
Enter query: {the query}
Enter query: results of the query

我希望实现在前缀'Enter query: '之前插入print函数的输出,或者看起来是这样做的:

Enter query: {the query}
results of the query
Enter query:

我已经考虑了几种方法,但没有找到一个好的解决方案。一个解决方法是通过添加'\x1b[1A\x1b[2K'来擦除前缀,并在查询执行输出后将其写回去。问题在于,此时我不知道如何重构可能已经被用户插入的不完整的用户输入(查询)。


如果你想要获取线程输出,那么 https://dev59.com/XGw15IYBdhLWcg3wA24A 应该可以做到。 - Natthaphon Hongcharoen
将消息和类似索引的内容返回,并将其写回到执行它的位置,是这个程序的要求吗? - Natthaphon Hongcharoen
你的主循环存储当前执行的数字,比如12,然后线程返回消息和索引10,所以你只需要回退2行。 - Natthaphon Hongcharoen
问题不在于读取线程的结果,而在于我想在第一个查询结果被处理时能够输入第二个查询,并且如果该线程产生输出,则应在新查询之前表示它,而不应中断未完成的查询。 - guenthermi
1个回答

2

使用从终端读取一个字符

  • 返回字节(bytes)
    • 通过 bytes.decode() 获取字符串(str)
  • 没有回显(输入不可见)
    • _GetchWindows.__call__中使用.getche替代msvcrt.getch
  • msvcrt没有全局导入

可以这样做

while input != '\r': # or some other return char, depends
    input += getch().decode()

并且

# in front of erase
while msvcrt.kbhit(): # read while there is something to read
    remember_input += getch().decode()
print(erase)
# and than you should return remember_input to stdin somehow (try msvcrt.putch)

由于复杂性(使用线程编写(我对此很陌生),输入/输出控制(因为这个原因,我的vsc终端每次都讨厌我),以及可能更多的原因我太累了无法想到),我自己没有完成过这个项目,但我相信你不会放弃。

编辑:哦,是的
我忘了提醒你,你也可能想要编写自己的printinput
在这种情况下,有用的东西将是input(prompt, remember_string)
提示将无法通过退格键擦除,而remember_string会

大更新
我使用模块代替msvcrt(如最初建议的那样)

这实际上涉及与您类似的问题(简化的模拟),
但解决了问题的核心

  1. 接收输入
  2. 发生某些事情时删除行并在该行中写入消息
  3. 重新输入已经编写的内容

这需要输入,只要它是<= 3个字符。
如果写入>= 4个字符,它将执行(3.)对于您来说是完成查询的操作,
然后再次要求输入旧输入。
按下ENTER键时,完成输入

import curses
import curses.ascii as ascii

def getch(stdscr: curses.window):
    'return single char'
    a = stdscr.get_wch()
    stdscr.refresh()
    return a

def prompt(stdscr: curses.window):
    'write prompt for input'
    addstr(stdscr, "Enter query: ")

def addstr(stdscr: curses.window, str):
    'write string to window'
    stdscr.addstr(str)
    stdscr.refresh()

def del_line(stdscr: curses.window):
    'deletes line in which cursor is'
    row, col = stdscr.getyx()
    stdscr.move(row, 0)
    stdscr.clrtoeol()

@curses.wrapper
def main(stdscr: curses.window):
    # next 3 lines were on some tutorial so I left them be
    # Clear screen
    stdscr.clear()
    curses.echo()

    # I will use marks like #x.y to indicate places
    q = ''
    while True: #EDIT from `for (5)` to `while`
        prompt(stdscr)
        addstr(stdscr, q) # at the beginning & after enter is pressed, q==''
                          # else it is old input (that was >= 4 chars
        for i in range(4): # range 4 to take 4 or less chars
            a = getch(stdscr) #read charby char
            if ascii.isalnum(a): #letters & numbers
                q += a
            elif a == '\n' or a == '\r': # enter pressed == input finished
                stdscr.addstr(f"\nfinished input {q}\n")
                q = ''
                break
        else: # this block happens (in py) if no break occurred in loop
            # that means, in this case, that ENTER was not pressed, i.e. input is stillongoing
            # but since it is > 4 chars it is briefly interrupted to write message
            del_line(stdscr)
            addstr(stdscr, "Input interupted\n")

    return 

测试
运行该程序(我建议双击文件以打开标准终端,因为其他终端可能会对此[程序]有所反感)
(E代表ENTER)
并输入:abcEabcdefEabcdefghijE
查看其效果

P.S.

这可能解决您的问题,但该模块的功能更大,
我不想写太多复杂的API。
解决方案是编写API以轻松管理更多事项,如使用箭头移动,但这不在本问题的范围内。


这至少是解决问题的第一步。谢谢 :) - guenthermi

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