7

在查看Python 内置函数列表时,我很难理解该方法的用处compile。我能找到的所有例子都指向一个简单的“hello world”。它的作用是有意义的但不是何时使用它。

这与 Python 用于生成 .pyc 文件的方法相同吗?

这可以用来消除 Python 的一些动态特性以提高某些代码块的性能吗?(完全清楚 C 中的模块是预编译模块的方式。)

4

2 回答 2

6

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

compileexec是和的低级版本eval。它不会执行或评估您的语句或表达式,而是返回一个可以执行此操作的代码对象。模式如下:

  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哪些完全不使用字节码缓存,应该如何使用。.pyc如果您将路径传递给文件,它不会神奇地检查是否有foo.py文件。

于 2013-07-27T18:32:51.507 回答
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

于 2013-07-27T18:38:41.307 回答