Python生成器函数在调用之间重置?

2024-10-03 15:23:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用ElementTree的iterparse函数解析XML文件中表示的语言词典。我用generator函数过滤它,一些奇怪的执行顺序误解给了我一个重复的条目。下面是一些设置代码(这实际上发生在函数内部,但其他细节无关紧要):

import xml.etree.cElementTree as ET
dictionary = iter(ET.iterparse("../dictionaries/language_name.xml", 
                  events=("start", "end"))) 
#We can discard the original iterable, I think

过滤

然后我有一个函数,它接收迭代器并过滤它(忽略全局变量,它只是为了调试问题):

^{pr2}$

加工

然后我这样使用它(同样,临时全局调试):

^{3}$

输出

如果我遍历所有内容,yielded = 9050,而received = 9051。以及有问题的输出:

Num received: 1
I got <entry><form>aː</form><ortho>a:</ortho><pos>dcadv</pos><sense><def><en>over here</en><es>acá</es></def></sense></entry>

Continue? 
Num yielded: 1
Yielding <entry><form>aː</form><ortho>a:</ortho><sgmtd /><pos>dcadv</pos><sense><def><en>over here</en><es>acá</es></def></sense></entry>

Num received: 2
I got <entry><form>aː</form><ortho>a:</ortho><sgmtd /><pos>dcadv</pos><sense><def><en>over here</en><es>acá</es></def></sense></entry>

Continue?
Num yielded: 2
Yielding <entry><form>aːčáx</form><ortho>a:cháj</ortho><pos>n</pos><sense><def><en>axe</en><es>hacha</es></def></sense></entry>

Num received: 3
I got <entry><form>aːčáx</form><ortho>a:cháj</ortho><pos>n</pos><sense><def><en>axe</en><es>hacha</es></def></sense></entry>

Continue?

问题

现在,我已经检查了,并且elem在循环开始之前没有定义。不,文件开头没有两个相同的元素。在第一个“我收到”字之后,一切似乎都按照我预期的方式工作——东西先被屈服,然后被接受(例如:首先屈服,然后被接受)。在

更奇怪的是,第一个元素在被生成之前被处理,而没有在for循环的末尾被清除。第一次“接收”时,它没有<;sgmtd>;节点。当它第一次“产生”时,它已经有一个<;sgmtd>;节点,表示它已被处理。然后它再次被接收,并且(尽管有一行是if not elem.find("sgmtd"): elem.insert(2, segmented_form))添加第二个<;sgmtd>;节点并将其写入文件。所以我的输出文件最终得到:

<?xml version="1.0" encoding="UTF-8"?>
<lexicon>
<entry><form>aː</form><ortho>a:</ortho><sgmtd /><pos>dcadv</pos><sense><def><en>over here</en><es>acá</es></def></sense></entry>
<entry><form>aː</form><ortho>a:</ortho><sgmtd /><sgmtd /><pos>dcadv</pos><sense><def><en>over here</en><es>acá</es></def></sense></entry>

我在这里误解了什么?在执行yield语句之前,如何从生成器函数“接收”一个项而没有任何代码?在

结果是,将if not elem.find("sgmtd")行改为if elem.find("sgmtd") is None会阻止重复项的处理。我猜Element对象不会像我预期的那样隐式转换为True。但我还是想知道它为什么会出现!


Tags: 函数posformhereesdefnumac
2条回答

@Chad Miller和{a2}都指出,我没有计算生成的根元素。这是有意的-我认为会发生的是我的生成器函数永远不会重置,就像生成器对象不会重置一样。所以当我开始用for elem in get_entries(dictionary)循环时,我认为根元素已经被消耗掉了。在

但是,如果在生成根元素之前添加print语句,它将被打印两次。我看到的数据重复是由于在根上调用elem.insert(2, segmented_form)引起的,其中segmented_form涉及使用{}(因此搜索其子元素)并获取树的第一个元素。在

所以:我看到重复的原因是因为生成器函数的行为与生成器对象不同。经验教训!在

你的过滤器里的计数器好像错了。在

您的计数器出现在内部循环中,并且只在该内部循环yield为某个值时递增。但是在生成器的开始处没有递增,它表示yield root。在

相关问题 更多 >