我正在玩一些python并想出了这段代码:
import time
N = 10000000
t1 = time.time()
for _ in range(N):
if 'lol' in ['lol']:
pass
print(time.time() - t1)
t1 = time.time()
for _ in range(N):
if 'lol' == 'lol':
pass
print(time.time() - t1)
所以,如果我使用python2
:
(test) C:\Users\test>python test.py
0.530999898911
0.5
(test) C:\Users\test>python test.py
0.531000137329
0.5
(test) C:\Users\test>python test.py
0.528000116348
0.501000165939
这很好 - 我喜欢第二种变体更快,我应该使用'lol' == 'lol'
,因为它是比较两个字符串更pythonic的方式。
但是如果我使用python3
会发生什么:
(test) C:\Users\test>python3 test.py
0.37500524520874023
0.3880295753479004
(test) C:\Users\test>python3 test.py
0.3690001964569092
0.3780345916748047
(test) C:\User\test>python3 test.py
0.37799692153930664
0.38797974586486816
使用timeit:
(test) C:\Users\test>python3 -m timeit "'lol' in ['lol']"
100000000 loops, best of 3: 0.0183 usec per loop
(test) C:\Users\test>python3 -m timeit "'lol' == 'lol'"
100000000 loops, best of 3: 0.019 usec per loop
我的天啊!为什么第一个变体更快?因此,当我使用'lol' in ['lol']
时,我应该使用像python3
这样丑陋的风格吗?
答案 0 :(得分:4)
你的python2时间大部分是通过调用range
来构建一个巨大的列表。在Python 2中将其更改为xrange
,或使用正确编写的timeit模块。一旦你完成了这一点,你就不会发现明显的差异,这会激发编写看起来很奇怪的代码。
答案 1 :(得分:3)
所以我应该使用丑陋的风格,如' lol'在[' lol']当我使用python3?
另外,正如其他人所说,您的测试用例存在缺陷:
$ python3 -m timeit "'lol' == 'lol'"
>> 10000000 loops, best of 3: 0.024 usec per loop
$ python3 -m timeit "'lol' in ['lol']"
>> 10000000 loops, best of 3: 0.0214 usec per loop
$ python2 -m timeit "'lol' == 'lol'"
>> 10000000 loops, best of 3: 0.0258 usec per loop
$ python2 -m timeit "'lol' in ['lol']"
>> 10000000 loops, best of 3: 0.0212 usec per loop
当涉及哪种比较更快时,python2和python3之间没有区别。
另一个混乱的原因可能是由于python解释器[1]在字符串缓存/实习方面的不透明行为。根据经验,短于四个字符的字符串是实际的,并且将引用相同的对象。它可以用类似
的东西进行测试a = 'lol'
b = 'lol'
a is b # tests for object id instead of applying an equality comparison
>> True
其他字符串也可能被实习,但一个简单的反例是包含特殊字符的4个字符的字符串之一:
a = '####'
b = '####'
a is b
>> False
当然,测试对象ID比进行实际比较更快,而使用in
进行测试就是这样。即使代码本身看起来很直接,但实际操作是出乎意料的。这也意味着略有不同的场景可能会导致令人惊讶的结果和有趣的错误。
总之,我再一次重复:不,你不应该更喜欢第二种比较变体。
[1]:Only CPython。我不知道其他python解释器是否做了类似的事情。