和
我在很多文章/资料中看到xrange(num)是一个生成器/迭代器。我有几个关于这方面的问题。<type'generator'>和<type'xrange'之间的差异
- 我想知道的类型“x范围”并键入“发电机”
-
之间的确切区别,如果x范围是一个迭代器/发电机,它应该具有的.next()方法。我不明白为什么.next()方法不适用于下面的情况。
def generator(): for i in xrange(20): yield i
在上述例子中,
numbers = generator() for i in numbers: if i == 6: break for i in numbers: if i == 10: break print i >>> 7 8 9 >>> print numbers.next() 11
上述功能也保持为真对的类型的对象生成:
>>> numbers = (x for x in range(100))
如果我做的xrange操作中,在循环开始从头开始迭代,没有next()操作。我知道,我们可以做的聪明的办法:
for i in xrange(20): if (#something): var = i break #perform some operations for i in range(var,20): #Do something
但我想循环VAR后继续不使用VAR。
简而言之,xrange是否有next()类型的操作。如果是的话:'怎么样?' ,否则:'为什么?'
xrange
是一个可迭代的,所以你可以调用iter
来得到一个迭代器。
>>> x = xrange(20)
>>> iterator = iter(x)
>>> for i in iterator:
... if i == 6: break
...
>>> iterator.next()
7
对不起,刚刚看到@Ryan在评论中打败了我。 – smarx
此外,你应该明白一个迭代器和一个生成器是不是一回事。 可迭代的是实现__iter__
方法的任何Python对象,该方法返回一个迭代器。迭代器还必须实现__iter__
方法,但也需要执行next
方法(Python 3中的__next__
)。所以xrange
是可迭代的,但不是迭代器。这里是一个迭代器:
class NumberCounter(object):
def __init__(self, size):
self.size = size
self.start = 0
def __iter__(self):
return self
def next(self):
if self.start < self.size:
self.start += 1
return self.start
raise StopIteration
在交互式解释:
>>> nc6 = NumberCounter(6)
>>> it = iter(nc6)
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
4
>>> next(it)
5
>>> next(it)
6
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in next
StopIteration
>>> for i in NumberCounter(6):
... print(i)
...
1
2
3
4
5
6
>>>
生成器是一个Python结构,可帮助您轻松地创建迭代。
从docs:
发生器是创建迭代器的简单而强大的工具。他们 是像常规函数一样编写的,但是只要他们想返回数据就使用yield语句 。每调用一次next(), 发生器就会从其停止的位置恢复(它记住所有数据值 值和上次执行的语句)...任何可以用发生器完成的 也可以用class为基础的迭代器,如前一节所述的 。什么让发电机如此紧凑, __iter __()和next()方法自动创建...在 除了自动方法创建和保存程序状态,当 发电机终止,他们自动提出StopIteration。在 组合中,与编写常规函数相比,这些功能可以轻松创建迭代器,而不需要更多的工作。
这里是发电机:
def number_counter(x):
curr = 1
while curr <= x:
yield curr
curr += 1
在交互式解释:
>>> for i in number_counter(6):
... print(i)
...
1
2
3
4
5
6
>>>
下面是另一个:
def wacky_gen():
yield 88
yield 2
yield 15
最后...
>>> for i in wacky_gen():
... print(i)
...
88
2
15
>>>
首先,你应该注意的x范围对象不是发电机:
>>> xrange_obj = xrange(10000)
>>> type(xrange_obj)
xrange
>>> gen_obj = (x for x in range(10000))
>>> type(gen_obj)
generator
>>> import types
>>> isinstance(xrange_obj, types.GeneratorType)
False
>>> isinstance(gen_obj, types.GeneratorType)
True
这是可迭代的(但不是一个迭代器)
>>> iter(xrange_obj)
<rangeiterator at 0x3e07f930>
>>> iter(xrange_obj).next()
0
最后,我没有看到它在目前的其他答案中提到,xrange不是一个生成器,但它自己的对象类型是因为它支持特殊的方法来使其模仿range
。
>>> xrange_obj[1]
1
>>> len(xrange_obj)
10000
>>> gen_obj[1]
TypeError: 'generator' object has no attribute '__getitem__'
>>> len(gen_obj)
TypeError: object of type 'generator' has no len()
不,因为它是可迭代的,而不是迭代器。你可以迭代多次。你可以使用'numbers = iter(xrange(20))'来获得该行为。 – Ryan
“我在很多帖子/资料中看到xrange(num)是一个生成器/迭代器。” - 这些帖子是错误的。人们只是不断说出来,因为他们不知道他们在说什么,并且因为他们喋喋不休地从他人那里听到了错误的事情。 – user2357112