解释python生成器的长列表

时间:2012-05-14 18:38:34

标签: python oop data-structures

我是新的python程序员,到目前为止我已经理解,“yield”关键字返回一个对象来代替生成器函数只返回生成器对象。

所以,如果我有一个包含10K项目的列表,我如何制作智能,pythonic解决方案,而不在列表中附加值并使其变大。

这意味着,我将一些值附加到列表中,最后创建一个大型列表,如下所示:

def example():
    final_list = []
    for i in range(0,10000):
        final_list.append(i)
    return final_list

这只是一个例子,不是真正的问题,我使用range()只是为了生成循环,在我的实际问题中,没有顺序数据,它将是随机字符串,而findla列表将包含10K串。 那么如何在不以有效的pythonic方式附加到列表的情况下获取所有值。

感谢。

7 个答案:

答案 0 :(得分:5)

你的例子已经过度简化了,所以让我们假装你想要10000个随机数。

创建生成器有两种方法。一个是yield语句:

def example():
    for i in xrange(10000):
        yield random.random()

另一种方法是使用generator expression

(random.random() for i in xrange(10000))

您选择哪一个取决于您的代码复杂性。

答案 1 :(得分:2)

如果我理解你,那么你只使用range(0, 10000)来模拟序列。无论何时在函数定义中使用yield,它都将成为生成器函数。当使用生成器函数(被调用)时,它返回迭代器 - 你没有看到它。请尝试以下gen()

def gen(n):
    while n > 0:
        yield n
        n -= 1    # decrement the value

然后你通常在循环中使用它:

for x in gen(10000):
    print x,         # comma to suppress new line

如果您有一个返回字符串的函数,只需yield s而不是构建列表。然后调用生成器函数并仅收集所需的值(此处不是字符串,但可以将整数除以100):

lst = []   # init
for x in gen(10000):
    if x % 100 == 0:
        lst.append(x)
print lst

循环也可以被所谓的列表理解所取代:

lst = [ x for x in gen(10000) if x % 100 == 0 ]
print lst

...当你写这样的内容时,这更容易理解(即类似于上面的循环):

lst = [ x 
        for x in gen(10000) 
            if x % 100 == 0 ]
print lst

但是你可以在任何需要序列的地方使用生成器函数。如果您的生成器可以决定是否要收集您的元素,那么您可以简单地列出生成的元素,如下所示:

lst = list(gen(100))
print lst

答案 2 :(得分:2)

你说:

  

我在抓取网页并附加这些字符串后会收到一些字符串   字符串到列表,作为抓取大型数据的爬虫,列表正在获取   更大,最后当我想迭代列表,它的时间和内存   耗时

所以:

# generator function to crawl web pages
def crawler():
    while iStillHaveWebPagesToCrawl():
        someStrings = getSomeStringsFromAWebPage()
        for aString in someStrings:
            yield aString

def oneStringAtATime():
    for aString in crawler():
        doSomethingWith( aString )

当您致电oneStringAtATime()时,它会设置名为crawler()的生成器功能;每次crawler()执行yield时,oneStringAtATime()中的循环都会使用该字符串迭代一次。当crawler()用完网页并退出该功能时,oneStringAtATime()循环将退出。

答案 3 :(得分:0)

好的,通过阅读问题/查看OP代码和下面的一些评论,看起来OP正在使用列表。

所以,

def example():
    final_list = range(0, 10000) # or xrange() for v 2.x
    return final_list

也可能没有临时的final_list变量,但为了清楚起见。

如果列表的值不是range / xrange生成的系列,那么list comprehension就适用于此。

仍然觉得这个问题有点不清楚。

答案 4 :(得分:0)

>>> xrange_object = xrange(10000)
>>> xrange_object[0]
0
>>> xrange_object[1]
1

我看到你编辑了你的问题。如果您有一个随机字符串生成函数ran_string,您可以使用生成器表达式来执行您想要的操作,如下所示:

>>> final_gen = (ran_string(i) for i in xrange(10000))

答案 5 :(得分:0)

你的问题不是很清楚 - 你在这里寻找的是generator expression

E.g:

>>> values = (random.random() for _ in range(10))
>>> for value in values:
...     print(value)
... 
0.32161489939829857
0.285715480204797
0.4961165128957876
0.42658612656828354
0.5083396364418685
0.00843781669361321
0.49698036590463757
0.8067300769956716
0.5741614069287628
0.4728079544997392

如果您想迭代所拥有的值,可以使用生成器表达式根据现有的iterable生成值,而无需预先构建列表。它们是在请求时生成的(在这种情况下,当循环请求它们时)。

检查上面链接的视频,以便更深入地解释生成器表达式的语法(以及所有它的表兄弟,列表组合,设置组合等...)。

答案 6 :(得分:0)

你的问题有点不清楚,但我会假设你的意思是你想要一个可以迭代的对象,但是它是懒惰的 - 即不会预先计算并存储所有值。

def example():
    for i in xrange(10000):
        yield i

g = example()
print g.next() # prints '0'
print g.next() # prints '1'
for x in g:
    print x # prints '2', '3', ..., '10000'

我在示例中使用了xrange,因为使用range会有点失败的目的,显然你可以在函数中放入你想要的任何东西。它的工作方式是g将记住它的内部状态(在这种情况下是i的值)并在每次调用g.next()或迭代g时运行到下一个yield语句。

我希望有所帮助!