欢迎访问宙启技术站
智能推送

Python生成器函数用法

发布时间:2023-06-13 23:07:27

Python生成器函数是一种特殊类型的函数,可以使用yield语句来生产值序列。生成器函数可以看作是一个生产值的工厂,每次使用next()函数或迭代时,生成器会自动执行代码,执行到yield语句时,会产生一个值并暂停当前函数,返回产生的值,待下次调用时继续从yield语句后继续执行。这样,我们不需要在内存中存储整个值序列,只需要每次生成一个值并返回,可以极大地节省内存空间,提高程序的效率。

下面是一个简单的生成器函数示例:

def gen():
    yield 1
    yield 2
    yield 3

g = gen()
print(next(g)) # 输出 1
print(next(g)) # 输出 2
print(next(g)) # 输出 3

生成器函数也可以用于迭代器中,可以使用for循环来迭代每个生成的值:

for i in gen():
    print(i)

# 输出:
# 1
# 2
# 3

使用生成器函数可以有效地避免对内存空间的大量消耗,还可以简化代码,增加代码可读性,加快程序的运行速度。下面我们来详细讲解一下生成器函数的用法。

1. 生成器函数的定义

生成器函数可以像普通函数那样定义,只需要在函数体中使用yield语句即可。比如:

def gen():
    yield 1
    yield 2
    yield 3

2. 生成器函数的调用

生成器函数不会立即执行,而是返回一个生成器对象。我们可以使用next()函数来调用生成器对象,每次调用都会从上次yield语句处继续执行,直到所有的yield语句都执行完毕,则会抛出StopIteration错误。

g = gen()
print(next(g)) # 输出 1
print(next(g)) # 输出 2
print(next(g)) # 输出 3
print(next(g)) # 抛出 StopIteration 错误

我们也可以使用for循环来迭代生成器对象的值:

for i in gen():
    print(i)

# 输出:
# 1
# 2
# 3

3. 生成器函数的应用

生成器函数可以用于处理大规模的数据集。比如,我们有一个包含一百万行数据的文件,如果我们使用列表来存储所有行,可能会占用大量的内存空间。这时候,我们可以使用生成器函数来逐行读取文件,一个一个地产生行作为生成器对象的值,这样既可以节省内存空间,又可以避免读取整个文件时导致程序崩溃。

def read_file(filename):
    with open(filename, 'r') as f:
        for line in f:
            yield line.strip()

for line in read_file('sample.txt'):
    print(line)

生成器函数还可以用于懒加载,比如我们有一个列表,如果列表中元素很多,而最后我们只需要其中的一部分元素时,我们可以使用生成器函数来逐个生成需要的元素,从而避免读取全部数据。

data = range(1000)

def lazy_filter(func, data):
    for item in data:
        if func(item):
            yield item

# 获取小于100的值
result = lazy_filter(lambda x: x<100, data)

# 输出结果
for item in result:
    print(item)

生成器函数还可以用于处理无限序列。在这种情况下,平常的迭代方法会一直执行,因为序列没有结束。但使用生成器函数,我们可以使用yield语句来定义序列,来限定序列的长度。

def gen():
    n = 0
    while True:
        n += 1
        yield n

# 获取前10个数
g = gen()
for i in range(10):
    print(next(g))

4. 生成器函数的特殊用法

使用生成器函数可以实现协程(coroutine),即多个线程之间的协作。协程是一种能够支持在单线程下实现多个函数相互控制的并发编程技术。通过yield语句,我们可以将函数挂起,等待其他函数的执行结束。这样可以避免线程切换等额外的开销,同时也避免了锁和共享变量造成的死锁等问题。

def produce():
    for i in range(1, 5):
        yield i

def consume(gen):
    for i in gen:
        print('consume', i)
        yield

# 模拟协程
p = produce()
c = consume(p)
for i in range(4):
    next(p) # produce
    next(c) # consume

除此之外,生成器函数还可以用于实现迭代器(iterator),可以自定义一个可迭代对象,使之能够被for循环迭代,并且可以实现__iter__()和__next__()方法。其中__iter__()返回一个迭代器对象,__next__()返回下一个元素,当没有元素时抛出StopIteration异常。

class MyRange():
    def __init__(self, start=0, end=10):
        self.start = start
        self.end = end
        
    def __iter__(self):
        self.x = self.start
        return self
    
    def __next__(self):
        if self.x < self.end:
            res = self.x
            self.x += 1
            return res
        else:
            raise StopIteration

for i in MyRange(1, 10):
    print(i)

5. 生成器表达式

除了生成器函数,Python还提供了一种简单的生成器表达式(generator expression)来创建生成器。生成器表达式使用类似于列表推导式的语法,但是使用小括号来包围,就可以得到生成器对象。

g = (x*x for x in range(1, 10))
print(next(g)) # 输出1
print(next(g)) # 输出4

使用生成器表达式可以避免创建完整的列表,也可以在需要时逐个生成值,从而避免对内存空间的大量消耗。同时,生成器表达式与生成器函数相比,在编码过程中代码更简短,更易于阅读。

本文介绍了Python生成器函数的用法,包括生成器函数的定义、调用、应用等,对于Python开发者来说,掌握生成器函数的使用可以提高程序运行效率,减少内存的占用,在处理大规模数据、做懒加载、协程等方面都可以发挥重要的作用。