为什么“范围为(1000000000000000(1000000000000001))”?Python 3这么快?

里克支持莫妮卡

据我了解,该range()函数实际上是Python 3中的一种对象类型,它会生成器一样动态生成其内容。

在这种情况下,我希望下一行会花费过多的时间,因为要确定1个四舍五入是否在范围内,必须生成一个四舍五入值:

1000000000000000 in range(1000000000000001)

此外:似乎无论我添加多少个零,计算多少都花费相同的时间(基本上是瞬时的)。

我也尝试过这样的事情,但是计算仍然是即时的:

1000000000000000000000 in range(0,1000000000000000000001,10) # count by tens

如果我尝试实现自己的范围函数,结果将不是很好!

def my_crappy_range(N):
    i = 0
    while i < N:
        yield i
        i += 1
    return

使range()物体如此之快物体在做什么


选择了Martijn Pieters的答案是因为它的完整性,但也看到了abarnert的第一个答案,它很好地讨论了在Python 3中range成为完整序列的含义,以及一些信息/警告,涉及__contains__整个Python实现中函数优化的潜在不一致之处abarnert的其他答案更加详细,并为那些对Python 3优化背后的历史(以及xrangePython 2中缺乏优化感兴趣的人提供了链接pokewim的答案感兴趣的人提供了相关的C源代码和说明。

马丁·彼得斯(Martijn Pieters)

Python 3range()对象不会立即产生数字。它是一个智能序列对象,可按需生成数字它包含的只是您的开始,结束和步进值,然后在对对象进行迭代时,每次迭代都会计算下一个整数。

该对象还实现了object.__contains__hook,并计算您的电话号码是否在其范围内。计算是一个(近)恒定时间运算*永远不需要扫描范围内的所有可能整数。

range()对象文档中

所述的优点range类型通过常规listtuple是一个范围对象将始终以相同的内存(小)数量,无论它代表的范围内的大小(因为它仅存储startstopstep值,计算各个项目和子范围如所须)。

因此,您的range()对象至少可以做到:

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, step = stop, start, -step
        else:
            lo, hi = start, stop
        self.length = 0 if lo > hi else ((hi - lo - 1) // 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

这仍然缺少实际range()支持的几项内容(例如.index().count()方法,哈希,相等性测试或切片),但应该可以给您一个提示。

我还简化了__contains__实现,只专注于整数测试。如果您为实物range()提供非整数值(包括的子类int),则会启动慢速扫描以查看是否存在匹配项,就像您对所有包含的值的列表使用了包含测试一样。这样做是为了继续支持其他数字类型,这些数字类型恰好支持整数的相等性测试,但也不希望也支持整数算术。请参阅实现收容测试的原始Python问题


*由于Python整数是无界的,因此时间接近恒定,因此数学运算也随着N的增长而及时增长,这使其成为O(log N)运算。由于所有操作均在优化的C代码中执行,并且Python将整数值存储在30位块中,因此,由于这里涉及的整数的大小,在看到任何性能影响之前,您将耗尽内存。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Python集排序,为什么这么快?

来自分类Dev

为什么初始化gl3w比初始化GLEW这么快?

来自分类Dev

为什么std :: rotate这么快?

来自分类Dev

为什么jQuery的$ .each这么快?

来自分类Dev

与SQLite相比,为什么Realm这么快?

来自分类Dev

为什么heapq.heapify这么快?

来自分类Dev

为什么Regex的Matches功能这么快?

来自分类Dev

为什么Numpy的克朗这么快?

来自分类Dev

为什么C#OrderBy这么快?

来自分类Dev

为什么`updatedb`程序运行这么快?

来自分类Dev

为什么SSD比原始NAND这么快?

来自分类Dev

为什么流浪汉这么快?

来自分类Dev

为什么在C#中我的计算比Python这么快

来自分类Dev

为什么重塑这么快?(剧透:写时复制)

来自分类Dev

为什么C#Array.BinarySearch这么快?

来自分类Dev

为什么`if`在语句前检查比在语句后检查这么快?

来自分类Dev

为什么像操作员这么快

来自分类Dev

为什么用jQuery元素包装元素这么快

来自分类Dev

为什么Eigens mean()方法比sum()这么快?

来自分类Dev

F#:为什么Array.createZero这么快?

来自分类Dev

为什么Clang这么快分配std :: complex?

来自分类Dev

为什么RSSurfaceView类被弃用这么快?

来自分类Dev

F#:为什么Array.createZero这么快?

来自分类Dev

为什么像操作员这么快

来自分类Dev

为什么Ext4磁盘检查比NTFS这么快?

来自分类Dev

为什么使用HTTPS over HTTP时HttpClient这么快?

来自分类Dev

为什么磁盘上的空间这么快用完?

来自分类Dev

为什么搜索空字符串这么快?

来自分类Dev

终端中的“定位”命令。为什么这么快?