4

在思考代码的优化时,我想知道在 python 中哪个更昂贵:

if x:
    d = 1
else:
    d = 2

或者

d = 2
if x:
    d = 1

有什么想法吗?我喜欢第二个中减少的行数,但想知道重新分配是否比条件切换更昂贵。

4

4 回答 4

20

不要思考,不要怀疑,测量——timeit 在 shell 命令行中使用(迄今为止最好、最简单的使用方法!)。笔记本电脑上 Mac OSX 10.5 上的 Python 2.5.4...:

$ python -mtimeit -s'x=0' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0748 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0685 usec per loop
$ python -mtimeit -s'x=0' 'd=2' 'if x: d=1'
10000000 loops, best of 3: 0.0734 usec per loop
$ python -mtimeit -s'x=1' 'd=2' 'if x: d=1'
10000000 loops, best of 3: 0.101 usec per loop

所以你看:与“if/else”形式相比,当 x 为假时,“just-if”形式可以节省 1.4 纳秒,但当 x 为真时需要 40.2 纳秒;因此,在微优化上下文中,只有当 x 是假的可能性比真的可能性高 30 倍时,才应该使用前者,或者大约。还:

$ python -mtimeit -s'x=0' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0736 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.076 usec per loop

... if/else 的三元运算符有其自己的小优点和缺点。

当差异如此微小时,您应该反复测量,确定噪音水平,并确保您没有将“噪音”中的差异视为显着。例如,要在“x 为真”的情况下比较语句与表达式 if/else,请重复几次:

$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.076 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0749 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0742 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0749 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0745 usec per loop

现在您可以声明表达式形式(在这台机器和关键软件的版本上)需要 74.2 到 76.0 纳秒——这个范围比任何单个数字都更具表现力。同样:

$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0688 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0681 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0687 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0679 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0692 usec per loop

现在您可以自信地声明语句形式(在相同条件下)需要 67.9 到 69.2 纳秒;所以它的优势,对于 x true,wrt 表达式形式,是 4.8 到 8.1 纳秒(将后一个间隔估计限制为 6.3 到 6.8 纳秒是相当公平的,比较 min/min 和 max/max 而不是 min/max 和 max/ min 作为更广泛、更审慎的估计)。

一旦你意识到它们微观的,那么有多少时间和精力值得花在这些微观差异上,当然,这是一个不同的问题。

于 2009-12-24T22:57:06.463 回答
5

您可能应该对此进行基准测试,但还有第三种形式使用三元运算符:

d = 1 if x else 2
于 2009-12-24T22:37:59.513 回答
2

第二个显然应该更昂贵,如果x为假,它执行相同的操作,如果为真,则执行两次分配x

假设:在 python 中赋值比条件跳转更昂贵,这是有道理的,因为它被解释并且它必须读取运行时哈希来获取新值,然后将其上传到相同的哈希中。

于 2009-12-24T22:36:42.013 回答
1

我会争辩说,最易读的那个是最优化的(至少在可读性方面)。

if...else 结构清楚地表明您正在处理一个非此即彼的情况。

如果 (d==2) 是通常的值并且您的 if 测试异常情况,则分配结构可能更有意义。如果你的分配远离 if,这个结构就变得不那么清楚了。

在这个简单的例子中,它并不重要。对于更复杂的代码,我几乎总是会优化可读性,即使是以几个 CPU 周期为代价。

于 2009-12-24T23:08:14.893 回答