Python 2.7.x 和 3.x 版本的重要区别小结(3)
由于xrange的“惰性求知“特性,如果只需迭代一次(如for循环中),range()通常比xrange()快一些。不过不建议在多次迭代中使用range(),因为range()每次都会在内存中重新生成一个列表。
在Python 3中,range()的实现方式与xrange()函数相同,所以就不存在专用的xrange()(在Python 3中使用xrange()会触发NameError)。
import timeit n = 10000 def test_range(n): return for i in range(n): pass def test_xrange(n): for i in xrange(n): pass
Python 2
print 'Python', python_version() print 'ntiming range()' %timeit test_range(n) print 'nntiming xrange()' %timeit test_xrange(n)
Python 2.7.6 timing range() 1000 loops, best of 3: 433 µs per loop timing xrange() 1000 loops, best of 3: 350 µs per loop
Python 3
print('Python', python_version()) print('ntiming range()') %timeit test_range(n)
Python 3.4.1 timing range() 1000 loops, best of 3: 520 µs per loop
print(xrange(10))
--------------------------------------------------------------------------- NameError Traceback (most recent call last) in () ----> 1 print(xrange(10)) NameError: name 'xrange' is not defined
Python 3中的range对象中的__contains__方法
另一个值得一提的是,在Python 3.x中,range有了一个新的__contains__方法。__contains__方法可以有效的加快Python 3.x中整数和布尔型的“查找”速度。
x = 10000000 def val_in_range(x, val): return val in range(x) def val_in_xrange(x, val): return val in xrange(x) print('Python', python_version()) assert(val_in_range(x, x/2) == True) assert(val_in_range(x, x//2) == True) %timeit val_in_range(x, x/2) %timeit val_in_range(x, x//2)
Python 3.4.1 1 loops, best of 3: 742 ms per loop 1000000 loops, best of 3: 1.19 µs per loop
根据上面的timeit的结果,查找整数比查找浮点数要快大约6万倍。但由于Python 2.x中的range或xrange没有__contains__方法,所以在Python 2中的整数和浮点数的查找速度差别不大。
print 'Python', python_version() assert(val_in_xrange(x, x/2.0) == True) assert(val_in_xrange(x, x/2) == True) assert(val_in_range(x, x/2) == True) assert(val_in_range(x, x//2) == True) %timeit val_in_xrange(x, x/2.0) %timeit val_in_xrange(x, x/2) %timeit val_in_range(x, x/2.0) %timeit val_in_range(x, x/2)
Python 2.7.7 1 loops, best of 3: 285 ms per loop 1 loops, best of 3: 179 ms per loop 1 loops, best of 3: 658 ms per loop 1 loops, best of 3: 556 ms per loop
下面的代码证明了Python 2.x中没有__contain__方法:
print('Python', python_version()) range.__contains__
Python 3.4.1 <slot wrapper '__contains__' of 'range' objects
print('Python', python_version()) range.__contains__
Python 2.7.7 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-7-05327350dafb> in <module>() 1 print 'Python', python_version() ----> 2 range.__contains__ AttributeError: 'builtin_function_or_method' object has no attribute '__contains__'
print('Python', python_version()) xrange.__contains__
Python 2.7.7 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) in () 1 print 'Python', python_version() ----> 2 xrange.__contains__ AttributeError: type object 'xrange' has no attribute '__contains__'
关于Python 2中xrange()与Python 3中range()之间的速度差异的一点说明: