我正在实现一个自定义(铁)Python 控制台。
一般来说,我需要显示一个>>>
提示,但是当一个语句不完整时,我需要将提示更改为...
并收集更多行,然后再执行它们。
我如何知道用户输入的一行是否完整,或者我是否需要阅读更多行?
一种简单的方法似乎是检查是否:
存在。但我不确定我是否没有错过其他:
不存在的情况。
我查看了 IronPython 源代码以了解它是如何做到这一点的,但是涉及到许多步骤,而且我的简单复制未能完全奏效。
我正在实现一个自定义(铁)Python 控制台。
一般来说,我需要显示一个>>>
提示,但是当一个语句不完整时,我需要将提示更改为...
并收集更多行,然后再执行它们。
我如何知道用户输入的一行是否完整,或者我是否需要阅读更多行?
一种简单的方法似乎是检查是否:
存在。但我不确定我是否没有错过其他:
不存在的情况。
我查看了 IronPython 源代码以了解它是如何做到这一点的,但是涉及到许多步骤,而且我的简单复制未能完全奏效。
仅通过查看冒号和括号的代码字符串来尝试猜测是不切实际的。你最终需要实现一半的 Python 解析器才能做到这一点。
标准库代码模块再现了交互式 Python 解释器的行为,我相信 IronPython 使用这个模块来实现其控制台。(CPython 本身并没有在 Python 中实现。)
您感兴趣的行延续逻辑来自codeop.compile_command函数。
这有点骇人听闻。本质上,它尝试compile()
使用 obscure 标志来处理给定的代码PyCF_DONT_IMPLY_DEDENT
,这意味着它不会假设任何打开的缩进在块的末尾自动关闭。然后它尝试添加换行符(导致显式 DEDENT)再次编译它。如果第二个有效但第一个无效,则您有可能继续,可以在块中输入更多内容。
repl 循环具有完整的知识和对解析器的访问权限。如果解析器的状态是它期望的不是语句,那么 repl 循环会产生一个...
. 在未闭合括号的情况下,下一行的语句将是非法的,因为没有可能包含语句的子表达式。在 a 之后:
,下一个预期的标记总是一个缩进,再一次声明总是非法的。这就是为什么总是需要在 repl 循环的缩进块的末尾键入一个空行,因为您必须为语句提供结束的缩进,才能成为下一个预期的生产规则。
我可以想到几种不同的方法来获得...
提示。
def foo():
x = (
x = {
x = [
x = '''
x = \
您是否使用了 a:
或 a \
(或未闭合的分隔符,如括号或括号)?交互式解释器显示一个...
.
实际的逻辑可能有点复杂,但这是基本规则。