一个Python3和Python2的range差异
Posted December 20, 2017
Python 3 中执行100000000 in range(100000001)
会比Python 2快的非常多。
$ time python -c "100000000 in range(100000001)"
python -c "100000000 in range(100000001)" 4.00s user 1.47s system 99% cpu 5.527 total
$ time python3 -c "100000000 in range(100000001)"
python3 -c "100000000 in range(100000001)" 0.04s user 0.01s system 86% cpu 0.055 total
如果把量级增高, Py2会出现 MemoryError
, Py3也会以非常快的速度执行。所以猜测Py3没有生成列表.
先看下两个方法的区别.
Python2
>>> dir(range)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Python3
>>> dir(range)
['__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index', 'start', 'step', 'stop']
可以看出有部分方法和属性的区别, 很明显Py3增强了 range 函数. 其实需要注意的是__contains__
, 这个函数支持了in
和not in
运算符, 所以完全可以通过,判断100000000
是否大于开始数字和结束数字即可完成in
和not in
运算.
如何用Py2实现Py3的range
注意代码中的__contains__
方法.
class my_range(object):
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = start, stop, step
if step < 0:
lo, hi = stop, start
else:
lo, hi = start, stop
self.length = ((hi - lo - 1) // abs(step)) + 1
def __iter__(self):
current = self.start
if self.step < 0:
while current > self.stop:
yield current
current += self.step
else:
while current < self.stop:
yield current
current += self.step
def __len__(self):
return self.length
def __getitem__(self, i):
if i < 0:
i += self.length
if 0 <= i < self.length:
return self.start + i * self.step
raise IndexError('Index out of range: {}'.format(i))
def __contains__(self, num):
if self.step < 0:
if not (self.stop < num <= self.start):
return False
else:
if not (self.start <= num < self.stop):
return False
return (num - self.start) % self.step == 0
整理翻译于StackoverFlow