我正在为一个比赛开发一个机器人,它通过sys.stdin
接收输入,并使用Python的print()
进行输出。我有以下内容:
import sys
def main():
while True:
line = sys.stdin.readline()
parts = line.split()
if len(parts) > 0:
# do stuff
问题是,输入是通过流进入的,使用上面的方法,会阻止我打印任何东西,直到流关闭。我能做些什么来使这个工作吗?
8条答案
按热度按时间iklwldmw1#
现在你可以使用
set_blocking
了。这可以在Linux上工作,并且可以通过改变fd的创建方式来适应其他系统。qyuhtwio2#
使用生成器-谢天谢地
sys.stdin
已经是一个生成器了!生成器使您能够处理无限流。当你调用它时,它总是返回下一个元素。为了生成一个生成器,你需要
yield
关键字。不要忘记在循环中放置一个
break
语句,如果某个特定的情况发生。您可以在以下网站找到有关发电机的更多信息:
cbjzeqam3#
通过禁用阻止,您一次只能读取一个字符。因此,没有办法让
readline()
在非阻塞上下文中工作。我假设你只是想通过按键来控制机器人。我在Linux上使用
select.select()
没有运气,并创建了一种调整termios
设置的方法。所以,这是Linux特定的,但对我来说很有效:一个更好的Windows或跨平台的答案在这里:Non-blocking console input?
tvmytwxo4#
您可以使用选择器来处理I/O多路复用:
https://docs.python.org/3/library/selectors.html
试试这个:
上面的代码将保持在线
直到注册事件发生,返回selector_key示例(k)和监视事件的掩码。
在上面的例子中,我们只注册了一个事件(Enter key press):
选择器键示例定义如下:
因此,register方法将
k.data
设置为我们的回调函数got_keyboard_data
,并在按下 Enter 键时调用它:一个更完整的例子(希望更有用)是将来自用户的stdin数据与来自网络的传入连接进行多路复用:
您可以使用两个终端进行测试。第一终端:
打开另一个终端并运行:
回到第一
结果(在主终端上显示):
xuo3flqw5#
s5a0g9ez6#
这是一个posix解决方案,类似于the answer by swdev。
正如他们所说,你必须使用
termios.VMIN
和termios.VTIME
来捕获多个字符,而不需要用户按Enter键。尝试只使用原始模式将是一个问题,因为像箭头这样的特殊键可能会扰乱下一次按键。这里我们使用
tty.setcbreak()
或tty.setraw()
作为快捷方式,但它们有short internals。请注意,您可以在此处添加两个可能的超时:
select.select()
4dc9hkyq7#
我可以推荐
nobreak
吗?如果你愿意使用诅咒。https://docs.python.org/3/library/curses.html#curses.window.nodelay
v1l68za48#
您应该能够读取流,
读取utf-8解码字符或:
读取原始字符。
如果我想从标准输入中获取原始数据并及时使用它做一些事情,而不需要先阅读换行符或填充内部缓冲区,我会这样做。这适用于在tty不可用的情况下通过ssh远程运行程序,请参阅:
要使程序在此场景中按预期工作,还需要考虑一些其他事情。您需要在完成后刷新输出,以避免缓冲延迟,并且当您只是没有刷新输出时,很容易假设程序没有读取输入。
但通常不是输入阅读的问题,而是提供输入流的终端(或程序)没有在您期望的时候移交它,或者可能没有在您期望的时候阅读您的输出。如果你有一个tty作为开始(见上面的ssh检查),你可以用tty模块将它置于raw模式。
.如果使用Mac/Linux。如果使用Windows,可以使用msvcrt.getch()。