专业编程基础技术教程

网站首页 > 基础教程 正文

一文带您理解Python生成器(generator):高效利用内存的奥秘

ccvgpt 2024-12-12 11:11:22 基础教程 1 ℃

Python的生成器(generator)实际上是返回可遍历对象/项列表的函数。这些函数不会一次性生成所有项,而是逐个生成,仅在需要时生成。每当使用for语句迭代一组项时,都会运行生成器函数。生成器是创建迭代器的一种强大而高效的方式。它们允许您随着时间生成一系列值,而不是一次性生成所有值并将它们保存在内存中。这使得它们特别适用于处理大型数据集或关注内存效率的情况。

生成器(generator)的优势

  • 在Python中,生成器生成可迭代对象将变得方便和简洁。
  • 生成器(generator)自动实现了__iter__()、next()、StopIteration,与迭代器(iterator) 组合实现起来十分方便。
  • 生成器生成的列表(items)仅在需要时生成,节省了内存,与普通Python函数不同。当您需要创建大量迭代器时,这一点变得非常重要。这是生成器的最大优势。
  • 可以用来生成无限数量项的列表。
  • 它们还可以用于在一系列操作中进行流水线处理。

普通函数与生成器函数

在Python中,生成器函数的创建方式与普通函数类似,都使用了 'def' 关键字。但是,生成器函数使用yield关键字而不是return关键字。这样做是为了通知解释器这是一个迭代器。生成器函数在调用next()函数时运行,而不是像普通函数那样通过函数名直接调用。考虑以下示例以更好地理解:

一文带您理解Python生成器(generator):高效利用内存的奥秘

from icecream import ic
def countlist(n):
    while n > 0:
        yield n
        n -= 1


g_cl=countlist(10)
ic(g_cl)
ic(next(g_cl))
ic(next(g_cl))
ic(next(g_cl))

在上面的输出中,func() 使用了 yield 关键字和 next 函数进行执行。

from icecream import ic
def count_list(n):
    result=[]
    while n > 0:
        result.append(n)
        n -= 1
    return result


g_cl=count_list(10)
ic(g_cl)
ic(g_cl[0])
ic(g_cl[1])
ic(g_cl[2])

使用生成器函数

Python中的生成器一次产生一个可迭代对象。看下面的例子:

def myfunc(a):
    i=0
    while i<a:
        yield i
        i=i+1


b =  myfunc(10)
ic(b)
ic(next(b))

在上面的示例中myfunc 函数中:满足while条件后返回了一个可迭代对象。执行调用生成器函数后,返回值为生成器对象,而不是值的列表。如果需要项的值,则通过调用next()函数得到列表项的值。

Python中的生成器函数自动实现了__iter__()和__next__()方法。因此,您可以通过简单地使用next()方法来迭代这些对象。当项生成应该终止时,生成器函数会在内部实现StopIteration,而无需担心调用者。

b =  myfunc(3)
ic(b)
ic(next(b))
ic(next(b))
ic(next(b))
ic(next(b))

上面的示例显示了多次执行next后再次调用next函数,将抛出StopIteration错误异常。

生成器与循环(loop)

如果想要迭代生成器的值列表,可以利用‘for’循环。这个循环帮助迭代对象,在所有实现之后执行StopIteration。

for i in myfunc(3):
  ic(i)

生成器表达式(Generator Expression)

表达式与for循环一起使用来生成迭代器。这通常使生成可迭代对象变得更加容易。生成器表达式类似于列表推导式(List Comprehension),并且与lambda函数类似,生成器表达式创建匿名生成器函数。

a=range(6)
ic("List Comprehension")
b=[x+2 for x in a] 
ic(b)
ic("Generator expression")
c=(x+2 for x in a) 
ic(c)
for y in c:
    ic(y)

生成器函数也可以在其他函数(min、max)中使用。例如:

a=range(6)
c=(x+2 for x in a) 
ic(c)
ic(min(c))
c=(x+2 for x in a) 
ic(max(c))

使用生成器函数/表达式以提高内存效率

我们看下面使用生成器表达式和列表推导式的情况下求min 最小值效率对比,在大体量的情况效率差距明显。

# 将 min() 与生成器表达式一起使用
data = range(100_000_000)
data_2=(x ** 2 for x in data)
result = min(data_2)
print(result)
# 将 min() 与列表推导式一起使用
data = range(100_000_000)
data_2=[x ** 2 for x in data]
result = min(data_2) 
print(result)

一亿条情况下:生成器表达式与min 一起求最小值所需时间:35秒,而列表推导式生成列表(list)min求最小值需要时间为:230秒。


Python的生成器(generator)是一种强大而高效的方式,用于创建迭代器,能够在需要时逐个生成值,而不是一次性生成并保存在内存中。生成器通过使用yield关键字,以及内部自动实现的__iter__()和__next__()方法,实现了高效的迭代处理。它们在处理大型数据集或关注内存效率时特别有用。生成器表达式和生成器函数的使用,以及与普通函数的比较,展示了生成器在内存效率上的显著优势。

Tags:

最近发表
标签列表