据我了解,函数range()实际上是 Python 3 中的一种对象类型,它动态生成其内容,类似于生成器。
在这种情况下,我预计下一行会花费不合理的长时间,因为必须生成千万亿的值来确定 1 千万亿是否在该范围内:
1000000000000000 in range(1000000000000001)
此外,似乎无论我添加多少个零,计算或多或少都会花费相同的时间(大部分是即时的)。
我也尝试过这样的事情,但计算仍然几乎是瞬时的:
1000000000000000000000 in range(0,1000000000000000000001,10) # С шагом в десять
如果我尝试实现自己的功能range,结果就不那么好了!!
def my_crappy_range(N):
i = 0
while i < N:
yield i
i += 1
return
对象的引擎盖下发生了什么range(),为什么偏移量如此之快?
@RicksupportsMonica翻译的问题为什么1000000000000000 in range(1000000000000001)在 python 3 中如此之快
在 Python 3 中,对象
range()不会立即产生数字。它是一个序列智能对象,可按需生成数字。它只包含开始、停止和步长值,然后当您迭代对象时,每次迭代都会计算下一个整数。该对象还实现
object.__contains__并计算您的数字是否在其范围内。计算是(几乎)恒定时间操作*。无需查看范围内所有可能的整数。来自对象的文档
range您的对象
range应如下所示:它仍然缺少真正支持的一些东西(例如or
range方法、散列、相等测试或切片),但它们应该给你一个想法。.index.count我还简化了实现
__contains__,只关注整数测试;如果您给一个真实对象一个range非整数值(包括子类int),则会开始慢速扫描以查看是否存在匹配项,就像您在所有包含值的列表上使用包含测试一样。这样做是为了继续支持其他数字类型,它们仅支持整数相等测试,但不应该也支持整数算术。请参阅实现包含测试的原始Python 问题。*几乎恒定的时间,因为 Python 整数不受限制,所以数学运算也随着时间增长
N,这使得这个运算O(log N)。因为这一切都是在优化的 C 代码中完成的,并且 Python 将整数值存储在 30 位块中,所以在注意到此处涉及的整数大小对性能产生任何影响之前,您将耗尽内存。关于成员@MartijnPieters的答案翻译
一个小小的补充(突然变大了!)
它实际上
__contains__看起来像这样这使得可以使用
__eq__所需对象的覆盖运算符因此,将花费更多时间来执行以下计算。
但是这个表达式将立即被评估
而且又慢了
嗯,值得一提的是,
__getitem__它还有效地实现了切片因此,你可以毫不犹豫地做
代替
它不疼。