【问题标题】:Print to console while waiting for input in python在等待 python 输入时打印到控制台
【发布时间】:2020-05-20 12:15:36
【问题描述】:

我有一个 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')

因此,打印函数的输出写在主线程第二次执行打印函数打印的前缀'Enter query: '后面:

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

我想实现在前缀'Enter query: '之前插入打印函数的输出(或者看起来是这样的):

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

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

【问题讨论】:

  • 如果你想得到线程输出,那么stackoverflow.com/questions/6893968/…应该这样做
  • 返回消息和诸如索引之类的东西并将其写回它可能被执行的位置?
  • 你的主循环存储当前执行的数字,比如 12,然后线程返回消息和索引 10,所以你只需要返回 2 行
  • 问题不在于读出线程的结果。问题是我希望能够在处理第一个查询结果时输入第二个查询,如果这个线程产生输出,它应该在新查询之前表示,并且不应该中断不完整的查询。

标签: python command-line-interface


【解决方案1】:

使用这个Read 1 char from terminal

  • 返回字节
    • 通过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 会

重大更新
我使用curses 模块而不是msvcrt(如最初建议的那样)

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

  1. 接收输入
  2. 发生某事时删除行并在该行中写入消息
  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 

测试
运行这个程序(我建议直接双击文件打开std终端,因为其他终端可能有针对这个[程序]的东西)
(E 代表 ENTER)
并输入:abcEabcdefEabcdefghijE
看看这是做什么的

附言

这可能会解决您的问题,但此模块的功能更大,
而且我不想写太多复杂的 API。
解决方案是编写 API 来轻松管理更多的事情,比如用箭头移动,但这不在这个问题的范围内

【讨论】:

  • 这至少是解决问题的第一步。谢谢你:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-25
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多