大吃一惊! 函数里面写生成器解析(生成器表达式),居然会这样.....

2017-03-16 11:16:41 +08:00
 aragakiiyui

make_index 这个函数就是简单的做一个倒排索引,将出现了某种语言的文章与该语言关联起来,返回的结果是一个列表,列表中每个元素是一个 tuple 。

from collections import namedtuple

WikipediaArticle = namedtuple("WikipediaArticle", ["title", "text"])


def make_index(langs, articles):
    result = []
    for lang in langs:
        # 创建包含该 lang 的文章的生成器
        article_gen = (article for article in articles if article.text.find(lang) >= 0) 
        result.append((lang, article_gen))
    return result

if __name__ == '__main__':
    articles = [
        WikipediaArticle('1', "Groovy is pretty interesting, and so is Erlang"),
        WikipediaArticle('2', "Scala and Java run on the JVM"),
        WikipediaArticle('3', "Scala is not purely functional"),
        WikipediaArticle('4', "The cool kids like Haskell more than Java"),
        WikipediaArticle('5', "Java is for enterprise developers")
    ]
	langs = ["Scala", "Java", "Groovy", "Haskell", "Erlang"]
    for item in make_index(langs, articles):
        print(item[0], list(item[1])
        

然后跑出来的结果是:

    Scala [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')]
    Java [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')]
    Groovy [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')]
    Haskell [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')]
    Erlang [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')]

很明显这结果有问题,取得都是第一条数据, 但是如果在函数内部做一点修改,会得到以下结果:

# result.append((lang, article_gen)) 这一句改成 result.append((lang, list(article_gen)))
('Scala', [WikipediaArticle(title='2', text='Scala and Java run on the JVM'), WikipediaArticle(title='3', text='Scala is not purely functional')])
('Java', [WikipediaArticle(title='2', text='Scala and Java run on the JVM'), WikipediaArticle(title='4', text='The cool kids like Haskell more than Java'), WikipediaArticle(title='5', text='Java is for enterprise developers')])
('Groovy', [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')])
('Haskell', [WikipediaArticle(title='4', text='The cool kids like Haskell more than Java')])
('Erlang', [WikipediaArticle(title='1', text='Groovy is pretty interesting, and so is Erlang')])

感觉好奇怪,为什么会这样,求解, 在函数里面解开生成器和在函数外面解开有什么区别吗?

5354 次点击
所在节点    Python
28 条回复
a87150
2017-03-16 13:09:10 +08:00
@aragakiiyui 看错了,是无意义的把 list 转换成 list

list(item[1])
aragakiiyui
2017-03-16 13:30:34 +08:00
@a87150 .......item[1]是 generator
@zhy0216 @ArieShout @oisc 嗯,我图形化代码的时候,发现所有的 generator 都指向了最后那个 lang 为 Erlang 的结果。 看了确实是 article 没变, lang 却变了。谢谢你们,我大概知道出错的原因了。但是还是不太理解里面的过程,请问哪里可以多了解这方面的知识?~
a87150
2017-03-16 13:46:09 +08:00
@aragakiiyui 你真傻还是装傻啊

result.append((lang, list(article_gen)))

你说 item[1]是不是 generator
zhy0216
2017-03-16 14:19:48 +08:00
@aragakiiyui
Finding closure with closures : <amp-youtube data-videoid="E9wS6LdXM8Y" layout="responsive" width="480" height="270"></amp-youtube>
aragakiiyui
2017-03-16 15:48:42 +08:00
@a87150 你是这里找到的吧 # result.append((lang, article_gen)) 这一句改成 result.append((lang, list(article_gen)))
这里是为了说明问题所做的比较啊大哥....关注点也是清奇。

所以请好好审题。明确别人问的是什么。然后丢合适的链接。要么就不答,要么就认真答。大家都是奔着解决问题去的。你这种回答态度很让人不舒服。 还好其他 v 友读懂了题目,给我上了一课。
falseen
2017-03-16 16:07:18 +08:00
aragakiiyui
2017-03-16 16:38:57 +08:00
@falseen 确实能找到 @a87150 不好意思,自己打脸了,我这下真心诚意接收你的建议,补基础去。收回前面的话~ sorry!!!
WKPlus
2017-03-17 09:59:26 +08:00
这是闭包的一个容易误解的地方嘛,等你把 generator 转成 list 的时候, generator 的代码开始执行,这时 lang 的值是 Erlang

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/347860

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX