据我了解,该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中缺乏优化)感兴趣的人提供了链接。poke和wim的答案为感兴趣的人提供了相关的C源代码和说明。
Python 3 range()对象不会立即产生数字。它是一个智能序列对象,可按需生成数字。它包含的只是你的开始,结束和步进值,然后在对对象进行迭代时,每次迭代都会计算下一个整数。
该对象还实现了object.__contains__hook
,并计算你的电话号码是否在其范围内。计算是一个(近)恒定时间运算*
。永远不需要扫描范围内所有可能的整数。
从range()
对象文档中:
所述的优点range
类型通过常规list
或tuple
是一个范围对象将始终以相同的内存(小)数量,无论它代表的范围内的大小(因为它仅存储start
,stop
和step
值,计算各个项目和子范围如所须)。
因此,你的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问题。
我刚开始编码。我想对同一个变量使用两次switch语句,我被告知要这样做,变量必须是'inscope'。 作为一个初学者,我不知道那是什么意思。那么在范围内意味着什么呢?而且,如果一个变量不在作用域中,我如何使它在作用域中?
问题内容: 在我的React组件中,我有一个带有onSubmit函数的表单 由于某种原因,当我使用表单onSubmit时不在范围内。当我在构造函数中时,道具会正常注销。 当我是窗口对象时。如何获得react组件的范围? 问题答案: 这是更广泛的问题,因为与此类似的行为在使用其他组件事件(例如onClick,onChange,onSubmit)时会注意到 在文档中有关于此的注释: https://f
问题内容: 我试图了解在多个JavaConfig上下文中放置注释的正确位置在哪里? 考虑以下情形:我在JPAConfig.java和AppConfig.java中具有服务bean集的JPA配置。然后,在RootConfig.java中编写整个应用程序配置。 我在JPAConfig.java中定义事务管理器,并启用对JPA存储库的扫描- 当这些暴露事务行为时,我将其放到JPAConfig上,并且它可
问题内容: Ada,Pascal和许多其他语言都支持范围,这是对整数进行子类型的一种方式。范围是一个有符号整数值,范围从一个值(第一个)到另一个值(最后一个)。实现一个在OOP中执行相同操作的类很容易,但是我认为本机支持该功能可以使编译器进行其他静态检查。 我知道无法静态地验证范围内定义的变量不会“溢出”运行时(即由于输入错误),但是我认为可以做些什么。我考虑了按合同设计方法(Eiffel)和Sp
如果我有一个Web应用程序,它的应用程序上下文加载了我的webapp和所有作业配置文件的所有内容,如果我的作业中有一个没有范围="步骤"的简单ItemReader,那么阅读器是单例的,对吗?所以如果我通过SimpleJobLauncher从控制器启动两次作业,我会使用同一个bean,对吗?除非我放入范围="步骤",以便每个作业执行一个bean? 另一方面,如果我从CommandLineJobRun
我对C#UTF8编码感到困惑... 假设这些“事实”是正确的: Unicode是定义每个字符的“协议” 根据C#参考,每个字符的可接受范围为0x0000到0xFFFF。我不明白另一个字符是什么,它在0xFFFF之上,在Unicode协议中定义的? 与C#相比,当我使用Python编写UTF8文本时-它涵盖了所有预期范围(0x0000到0x10FFFF)。例如: 这对C不起作用。此外,当我将Pyth