假设我有:
def func(n):
for i in range(1,100000,2*n+3):
...
很明显,step = 2*n+3
部分计算一次。
但xrange
根据this answer,xrange
是一个懒惰评估的序列对象。
所以问题基本上是 - 哪个部分懒惰评估?
只是start <= stop
部分,还是step
部分?
我尝试了一个简单的测试来确定答案:
n = 1
for a in xrange(0,100,n):
print a
n += 1
此测试清楚地表明在每次迭代时都不会重新评估n
。
但是我怀疑n
表达式中的xrange
可能与n
之前声明的xrange
的范围不同。“ / p>
谢谢。
答案 0 :(得分:4)
range()
和xrange()
都不关心步骤值的推导方式;执行表达式并将表达式的结果传递给调用,即range()
,xrange()
或任何其他可调用对象。
那是因为(...)
也是一个表达;它是call expression;传递给调用的参数是在结果传递给调用之前计算的所有表达式。这里所谓的内容并不重要。
TLDR; xrange()
对象传递表达式的结果,而不是表达式本身。只要该结果是一个整数对象,它就会被对象存储(作为一个不可变的值)来基于虚拟序列。
答案 1 :(得分:2)
xrange
懒惰地工作的事实意味着 参数在<#34;&#34;&#34;&#34;时间 xrange
(实际上xrange
从来不知道表达式是什么),但是元素会被懒散地生成。因此,在您调用step
之前,xrange(..)
参数实际上是计算出来的。因此,xrange(..)
不知道该步骤的计算方式,因此无法要求重新评估该步骤。
虽然xrange(..)
比这更复杂(因为它可以使用否定步骤等),但是一个非常基本的实现是:
def xrange(frm,to,step):
i = frm
while i < to:
yield i
i += step
答案 2 :(得分:2)
添加其他答案:测试此方法的一个好方法是提供一个函数作为步骤参数。如果要多次评估,则需要多次调用该函数。
foo was called
0
25
50
75
以上代码输出
document.getElementsByClassName()
表明步骤参数只被评估一次。
答案 3 :(得分:2)
当你将适当的参数传递给xrange()
时,Python将构建一个生成器对象,它将动态地计算值&#34;。
构造并返回该生成器对象后,将设置该对象。 它不再关心最初用于计算其构造函数参数的变量是否发生了变化 。
同样的原则不仅适用于xrange()
,也适用于其他可调用对象。一旦将参数传递给可调用函数,Python就会使用任何变量的当前值计算表达式,并将结果传递给callable。如果用于计算可调参数的参数的任何变量的值已更改,则Python不关心,因为仅使用了变量的当前值。 每次传递给它的表达式中使用的变量发生变化时,Python都不会重新计算函数的参数 :
>>> n = 10
>>> xr = xrange(n)
>>> n += 1
>>> n
11
>>> list(xr)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
答案 4 :(得分:1)
懒惰评估并不意味着您可以在评估过程中更改评估;在迭代step
时,您正在处理使用您提供的参数创建的生成器。它在迭代期间无法更改其Rails.logger.info('Event happened',
{ event_id: '...', email: '...', ...}
)
,至少不能使用内置的{。}}。