2013-03-15 42 views
1

我已经在Python,其中ori是一个字符串Python能否避免在语句中重新评估?

 
[ori[ori.rfind(' ') + 1:], ori[:ori.rfind(' ')]] 

我们可以看到ori.rfind(”“)被调用了两次,是解释足够聪明下面的语句只是计算函数只有一次?

我们可以做到以下几点:

 
    s = ori.rfind(' ') 
    return [ori[s+1:], ori[:s]] 

但这种利用两行。我打算在列表理解中使用这个语句,并希望这个函数是一行。

在这种情况下,解释器实际上更容易理解,因为字符串是不可变的。我的猜测可能是解释者可以聪明地避免重新评估。一般来说,如果对象是不可变的,解释器是否足够聪明?

+1

“使用两行很少pythonic”?! – NPE 2013-03-15 17:29:18

+3

为什么它会变得不那么pythonic? – 2013-03-15 17:29:27

+0

在几乎所有情况下,使用两行*都是不正确的*。当它是正确的时候,它很少重要。当它是正确的并且很重要时,通常很难自动完成。 – delnan 2013-03-15 17:34:40

回答

2

解释器可以安全地执行子表达式ori.rfind(' ')的唯一方法是一次,如果它知道

  1. 的RFIND表达没有进行任何突变
  2. 第一和第二使用rFind之间没有表情引起的任何突变

如果有任何这不是真的,那么缓存结果和重用会根本不安全。鉴于Python的动态特性,几乎不可能拥有这些保证,因此像这样的操作无法缓存+重用

+0

+1,这是一个非常好的解释,为什么建议的优化不起作用。 – 2013-03-15 17:43:12

+0

@Lattyware公平地说,真正的问题是可以在任何角落重新定义方法。提到的所有其他问题都由Java共享,但Hotspot JIT在优化代码时没有问题(假设'rfind'不会影响内联预算)。事实上,热点设法消除虚拟调用并修复问题,如果它的假设后来失效,因此只要有足够的工程努力,就没有任何东西可以阻止python运行时间这样做。 – Voo 2013-03-15 17:50:59

+1

正在重新定义的方法只是突变的一个特例。 – 2013-03-15 17:52:41

5

我不认为你可以指望解释评估函数只有一次,但这里是您当前的代码等量替代是短,类似于效率两线法:

ori.rsplit(' ', 1)[::-1] 

实施例和定时比较:

In [1]: ori = 'foo bar baz' 

In [2]: [ori[ori.rfind(' ') + 1:], ori[:ori.rfind(' ')]] 
Out[2]: ['baz', 'foo bar'] 

In [3]: ori.rsplit(' ', 1)[::-1] 
Out[3]: ['baz', 'foo bar'] 

In [4]: %timeit [ori[ori.rfind(' ') + 1:], ori[:ori.rfind(' ')]] 
1000000 loops, best of 3: 732 ns per loop 

In [5]: %timeit ori.rsplit(' ', 1)[::-1] 
1000000 loops, best of 3: 514 ns per loop 

In [6]: %timeit s = ori.rfind(' '); [ori[s+1:], ori[:s]] 
1000000 loops, best of 3: 490 ns per loop 
+0

(+1)不知道有' rsplit()'。 – NPE 2013-03-15 17:32:08

+0

真的很感谢你提到rsplit以及实验!但我觉得另一个答复更直接地回答了我的问题,所以我接受了这个答案。 – szli 2013-03-15 20:48:03