PyMongo不会迭代收集

时间:2012-03-20 15:20:36

标签: python pymongo

我在Python / PyMongo中有奇怪的行为。

dbh = self.__connection__['test']
first = dbh['test_1']
second = dbh['test_2']

first_collection_records=first.find()  
second_collection_records=second.find()


index_f=first_collection_records.count() //20 
index_s=second_collection_records.count() //120

i=0
for f in first_collection_records:
    for s in second_collection_records:
         i=i+1
         print i

并且它只打印120次(1..120)而不是20x120次。有人能告诉我为什么它不会迭代外部集合?我打印结果,它总是只取第一个外部并迭代内部集合。 (我发布了我在代码20和120中获得的计数,我尝试使用xrange并通过索引获取但没有任何内容)

1 个答案:

答案 0 :(得分:8)

如果你想为每个first_collection_records迭代second_collection_records,你可以使用:

i=0
for f in first_collection_records:
    second_collection_records.rewind() #Reset second_collection_records's iterator
    for s in second_collection_records:
         i=i+1
         print i

.rewind()将光标重置为新状态,使您能够再次检索second_collection_records中的数据。


<强>解释

second.find()

返回一个Cursor对象,其中包含一个迭代器。

当Cursor的迭代器到达它的末尾时,它不再返回任何内容。

因此:

for f in first_collection_records: #20

实际上迭代了20次,但自内部:

for s in second_collection_records:

已经迭代了所有返回的对象,第二次调用它时,second_collection_records不再返回任何内容,因此内部代码(i = i + 1,print ...)不会被执行。

你可以这样试试:

i = 0
for f in first_collection_records:
    print "in f"
    for s in second_collection_records: 
        print "inside s"

你会得到一个结果:

inside f
inside s
inside s
...
inside s
inside f  <- since s has nothing left to be iterated, 
             (second_collection_records actually raised StopIteration such in generator),
             code inside for s in second_collection_records: is no longer executed
inside f
inside f

深入解释:

这一行:

for s in second_collection_records: 

这里的循环实际上是由Cursor对象的next()方法工作,如:调用second_collection_records.next()直到second_collection_records引发StopIteration异常(在Python生成器和for循环中,StopIteration被捕获并且for循环中的代码不会执行)。所以在first_collection_records的第二个直到最后一个循环中,second_collection_records.next()实际上为内循环引发了StopIteration,而没有执行代码。

我们可以通过这样做轻松地观察到这种行为:

for f in first_collection_records:
    print "inside f"
    second_collection_records.next()
    for s in second_collection_records:
        print "inside s"

结果:

inside f
inside s
...
inside s
inside f
Traceback (most recent call last):
  ... , in next
    raise StopIteration
StopIteration