29.2. codeop —编译 Python 代码

codeop模块提供 Util,可以在这些 Util 上模拟 Python read-eval-print 循环,就像在code模块中一样。结果,您可能不想直接使用该模块。如果要在程序中包含这样的循环,则可能要使用code模块。

这项工作分为两个部分:

  • 能够判断 Importing 行是否完成了 Python 语句:总之,告诉接下来要打印'>>>还是'...'。

  • 记住用户已经 Importing 了哪些将来的语句,因此后续的 Importing 可以有效地进行编译。

codeop模块提供了完成所有这些操作的方法,以及同时完成这两项操作的方法。

要做前者:

  • codeop. compile_command( [,文件名 [,符号]])
    • try编译* source ,它应该是 Python 代码的字符串,如果 source 是有效的 Python 代码,则返回一个代码对象。在这种情况下,代码对象的 filename 属性将是 filename ,默认为'<input>'。如果 source *不是有效的 Python 代码,但是是有效的 Python 代码的前缀,则返回None

如果* source *存在问题,将引发异常。如果使用无效的 Python 语法,则引发SyntaxError;如果使用无效的 Literals,则引发OverflowErrorValueError

  • symbol 参数确定 source *是编译为语句('single',默认值)还是expression('eval')。其他任何值都会导致ValueError升高。

Note

解析器有可能(但不太可能)在到达源末尾之前停止以成功结果进行解析;在这种情况下,尾随的符号可能会被忽略而不是引起错误。例如,反斜杠后跟两个换行符,后跟任意乱码。一旦解析器的 API 更好,此问题将得到修复。

  • 类别 codeop. Compile

    • 此类的实例具有与内置函数compile()签名相同的call()方法,但不同之处在于,如果该实例编译包含future语句的程序文本,则该实例“记住”并使用有效的语句编译所有后续程序文本。 。
  • 类别 codeop. CommandCompiler

    • 此类的实例具有与compile_command()签名相同的call()方法;不同之处在于,如果实例编译包含__future__语句的程序文本,则该实例“记住”并在有效的语句下编译所有后续程序文本。

关于版本兼容性的说明:CompileCommandCompiler是 Python 2.2 中的新增Function。如果要启用 2.2 的将来跟踪Function,但又要保持与 2.1 和 Python 早期版本的兼容性,则可以编写

try:
    from codeop import CommandCompiler
    compile_command = CommandCompiler()
    del CommandCompiler
except ImportError:
    from codeop import compile_command

这是一个影响很小的更改,但是可能会在程序中引入不必要的全局状态,或者您可以编写:

try:
    from codeop import CommandCompiler
except ImportError:
    def CommandCompiler():
        from codeop import compile_command
        return compile_command

然后在每次需要新的编译器对象时调用CommandCompiler