编译器优化常量操作

时间:2015-09-18 22:36:19

标签: python optimization compilation

下面的第0个循环比第1个循环运行得快得多(Python-2.7为3倍,Python-3.4为5倍):

for x in range(0,999999):
    "u" in {"a", "e", "i", "o", "u"}

for x in range(0,999999):
    "u" in set("aeiou")

似乎Python在给定{"a", "e", "i", "o", "u"}时构建了一次集合,但是当给定set("aeiou")时,每次需要时都会构建集合。

这是对的吗?如果是这样,为什么Python不优化后者?

* 使用time python -c '<code>'

衡量

4 个答案:

答案 0 :(得分:1)

您在每个循环中调用构造函数。再试一次:

canvasImg.toDataURL( "image/jpeg", 1.0 )

这给出了时间:

import time

start = time.time()
for x in range(0,999999):
    "u" in {"a", "e", "i", "o", "u"}
print time.time() - start, "for dictionary look-up"

start = time.time()
for x in range(0,999999):
    "u" in ["a", "e", "i", "o", "u"]
print time.time() - start, "for list look-up"    start = time.time()

for x in range(0,999999):
    "u" in set("aeiou")
print time.time() - start, "for set construction"

start = time.time()
vowel = set("aeiou")
for x in range(0,999999):
    "u" in vowel
print time.time() - start, "for set reference"

答案 1 :(得分:1)

我根据你的片段(分别来自#0和#1)创建了函数f1和f2。然后我使用dis模块。简而言之,您可以看到在循环内的第二种情况下调用了集合构造函数(第二种情况中为31)。而一个常数只是在第一个中加载(第一个中的25个)。

In [20]: dis.dis(f1)
  2           0 SETUP_LOOP              33 (to 36)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (0)
              9 LOAD_CONST               2 (999999)
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
             15 GET_ITER
        >>   16 FOR_ITER                16 (to 35)
             19 STORE_FAST               0 (x)

  3          22 LOAD_CONST               3 ('u')
             25 LOAD_CONST               8 (frozenset({'e', 'o', 'a', 'u', 'i'}))
             28 COMPARE_OP               6 (in)
             31 POP_TOP
             32 JUMP_ABSOLUTE           16
        >>   35 POP_BLOCK
        >>   36 LOAD_CONST               0 (None)
             39 RETURN_VALUE

In [21]: dis.dis(f2)
  2           0 SETUP_LOOP              39 (to 42)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (0)
              9 LOAD_CONST               2 (999999)
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
             15 GET_ITER
        >>   16 FOR_ITER                22 (to 41)
             19 STORE_FAST               0 (x)

  3          22 LOAD_CONST               3 ('u')
             25 LOAD_GLOBAL              1 (set)
             28 LOAD_CONST               4 ('aeiou')
             31 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             34 COMPARE_OP               6 (in)
             37 POP_TOP
             38 JUMP_ABSOLUTE           16
        >>   41 POP_BLOCK
        >>   42 LOAD_CONST               0 (None)
             45 RETURN_VALUE

答案 2 :(得分:1)

Python解释器不会将set("aeiou")识别为常量,因为尽管告诉"aeiou"不会发生变化这一点很简单,但要难得多判断set函数是否会改变。

解释器可以检查set()是否未在循环内的任何位置重新分配,但我想麻烦不值得。

答案 3 :(得分:0)

在第一种情况下,您在编译时创建一次集合(当python代码编译为python byte-ops时)。在第二个中,你为循环的每次迭代创建一次。