Python内置的'compile'主要用途是什么?

8
当查看Python内置函数列表时,我很难理解compile方法的实用性。我找到的所有示例都指向一个简单的“hello world”。我知道它做了什么,但不知道何时使用它。
这是Python用于生成.pyc文件的相同方法吗?
这可以用于消除Python的某些动态特性,以改善某些代码块的性能吗?(完全知道C模块是预编译模块的正确选择。)
2个回答

6
从这里开始:Python 中 eval、exec 和 compile 的区别是什么?

compileexeceval 的低级版本。它不执行或评估你的语句或表达式,但返回一个可以执行它们的代码对象。模式如下:

  1. compile(string, '', 'eval') 返回代码对象,该对象将在执行 eval(string) 时执行。请注意,你不能在此模式下使用语句;只有(单个)表达式有效。
  2. compile(string, '', 'exec') 返回代码对象,该对象将在执行 exec(string) 时执行。你可以在此处使用任意数量的语句。
  3. compile(string, '', 'single') 类似于 exec 模式,但它将忽略除第一条语句以外的所有内容。请注意,带有其结果的 if/else 语句被认为是单个语句。

更新:

何时编译 Python?

通常情况下,编译 Python 可以利用性能。已编译的代码具有更快的启动时间,因为它不必编译,但它不会运行更快

最重要的是,如果你想手动将代码转换成字节码,则应使用 compile。这引出了另一个重要但相关的问题为什么要这样做?

正如在这篇杰出的文章中所提到的:

如果要使用 exec 并且计划多次执行该代码,请确保将其先编译为字节码,然后仅在新字典(即命名空间)中执行该字节码。

值得注意的是:

现在执行字节码相比于创建并执行字节码会快多少呢? $ python -mtimeit -s 'code = "a = 2; b = 3; c = a * b"' 'exec code' 10000次循环,最好的3次结果:每次22.7微秒 $ python -mtimeit -s 'code = compile("a = 2; b = 3; c = a * b","", "exec")' 'exec code' 1000000次循环,最好的3次结果:每次0.765微秒 对于一个非常短的代码示例来说,速度快了32倍。但是,当代码量增加时,情况会变得更糟。为什么?因为将Python代码解析并转换为字节码是一项昂贵的操作,与评估字节码相比。当然,这也影响到了execfile,它完全不使用字节码缓存,它怎么可能呢?如果您传递foo.py文件的路径,它不会神奇地检查是否有.pyc文件。

这是我收集到的关于它的信息,但仍不清楚何时/为什么使用它。唯一想到的是在调用“eval”/“exec”之前进行快速检查以查看是否存在任何语法错误。 - Adam Lewis
@AdamLewis,抱歉。已更新。 - jrd1
1
很棒的更新。我有一种预感,它只在使用exec内置函数时才真正有用。感谢您花时间阐明这个话题。 - Adam Lewis

2
回答关于动态性的问题,实际上并没有。生成的代码对象仍然是解释执行的;相同的字节码仍然运行。
我见过使用compile()(和代码生成)最有用/令人印象深刻的例子是在Jinja2中。它实际上从你的模板生成Python代码,然后使用compile使其以“本地”(==解释器)速度运行,如果这样说有意义的话。

https://github.com/mitsuhiko/jinja2/blob/master/jinja2/environment.py#L506

与之相比,例如django.template,在“用户空间”中执行变量查找等操作(再次强调,这只是个比喻,有点奇怪)。

https://github.com/django/django/blob/master/django/template/base.py#L752


我之前都用过 Django 和 Jinja,但从未深入了解过模板系统。我同意这是处理模板的一种很好的方式。也许这就是我在 Django 中使用 Jinja 作为模板系统的原因之一 :) - Adam Lewis

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