0

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

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

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

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

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

谢谢。

4

7 回答 7

5

您的示例过于简化,所以让我们假设您想要 10000 个随机数。

有两种方法可以创建生成器。一个是yield声明:

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

另一种方法是使用生成器表达式

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

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

于 2012-05-14T18:59:40.360 回答
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()循环退出。

于 2012-05-14T21:50:20.003 回答
2

如果我理解你,那么你使用range(0, 10000)only 来模拟序列。每当您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
于 2012-05-14T18:58:17.857 回答
0

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

所以,

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

也可以不使用临时 final_list 变量,但为了清楚起见。

如果列表的值不是由 range/xrange 生成的系列,那么列表理解在这里是合适的。

还是觉得这个问题有点不清楚。

于 2012-05-14T18:40:13.667 回答
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))
于 2012-05-14T18:43:53.617 回答
0

你的问题不是很清楚 - 你在这里寻找的是一个生成器表达式

例如:

>>> 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

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

查看上面链接的视频,以更深入地解释生成器表达式的语法(以及它的所有表亲、列表组合、集合组合等......)。

于 2012-05-14T18:45:26.223 回答
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 语句。

我希望这会有所帮助!

于 2012-05-14T19:04:37.290 回答