亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> Python

Python 生成器

Python 生成器

在本教程中,您将学习如何使用 Python 生成器轻松创建迭代,它与迭代器和普通函数有何不同,以及为什么要使用它。

视频:Python 生成器

Python 中的生成器

在 Python 中构建迭代器需要做很多工作。我们必须用 __iter__() 实现一个类 和 __next__() 方法,跟踪内部状态,并引发 StopIteration 当没有要返回的值时。

这既冗长又违反直觉。在这种情况下,生成器会来救援。

Python 生成器是一种创建迭代器的简单方法。我们上面提到的所有工作都是由 Python 中的生成器自动处理的。

简单来说,生成器是一个函数,它返回一个我们可以迭代的对象(迭代器)(一次一个值)。


在 Python 中创建生成器

在 Python 中创建生成器相当简单。就像定义一个普通函数一样简单,但是使用 yield 语句而不是 return 声明。

如果一个函数至少包含一个 yield 语句(它可能包含其他 yieldreturn 语句),它成为一个生成器函数。 yieldreturn 将从函数中返回一些值。

不同的是,虽然 return 语句完全终止一个函数,yield 语句暂停函数保存其所有状态,然后在后续调用中从那里继续。


Generator函数和Normal函数的区别

以下是生成器函数与普通函数的不同之处。

这是一个示例来说明上述所有要点。我们有一个名为 my_gen() 的生成器函数 有几个 yield 声明。

# A simple generator function
def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n

下面给出了解释器中的交互式运行。在 Python shell 中运行这些以查看输出。

>>> # It returns an object but does not start execution immediately.
>>> a = my_gen()

>>> # We can iterate through the items using next().
>>> next(a)
This is printed first
1
>>> # Once the function yields, the function is paused and the control is transferred to the caller.

>>> # Local variables and theirs states are remembered between successive calls.
>>> next(a)
This is printed second
2

>>> next(a)
This is printed at last
3

>>> # Finally, when the function terminates, StopIteration is raised automatically on further calls.
>>> next(a)
Traceback (most recent call last):
...
StopIteration
>>> next(a)
Traceback (most recent call last):
...
StopIteration

在上面的例子中要注意的一件有趣的事情是变量 n 的值 每次通话之间都会被记住。

与普通函数不同,局部变量在函数产生时不会被破坏。此外,生成器对象只能迭代一次。

要重新启动该过程,我们需要使用类似 a = my_gen() 的东西创建另一个生成器对象 .

最后要注意的一点是,我们可以直接使用带有 for 循环的生成器。

这是因为 for 循环接受一个迭代器并使用 next() 对其进行迭代 功能。 StopIteration 时自动结束 被提出。查看此处了解 Python 中 for 循环的实际实现方式。

# A simple generator function
def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n


# Using for loop
for item in my_gen():
    print(item)

当你运行程序时,输出将是:

This is printed first
1
This is printed second
2
This is printed at last
3

带循环的 Python 生成器

上面的例子用处不大,我们研究它只是为了了解背景中发生的事情。

通常,生成器函数是通过具有适当终止条件的循环来实现的。

让我们以一个反转字符串的生成器为例。

def rev_str(my_str):
    length = len(my_str)
    for i in range(length - 1, -1, -1):
        yield my_str[i]


# For loop to reverse the string
for char in rev_str("hello"):
    print(char)

输出

o
l
l
e
h

在这个例子中,我们使用了 range() 使用for循环以相反顺序获取索引的函数。

注意 :这个生成器函数不仅适用于字符串,还适用于其他类型的可迭代对象,如列表、元组等。


Python 生成器表达式

使用生成器表达式可以轻松地动态创建简单的生成器。它使构建生成器变得容易。

与创建匿名函数的 lambda 函数类似,生成器表达式创建匿名生成器函数。

生成器表达式的语法类似于 Python 中的列表推导式。但是方括号被圆括号代替了。

列表推导式和生成器表达式的主要区别在于,列表推导式生成整个列表,而生成器表达式一次生成一个项目。

他们有惰性执行(仅在被要求时才生成项目)。因此,生成器表达式比等效的列表推导式更节省内存。

# Initialize the list
my_list = [1, 3, 6, 10]

# square each term using list comprehension
list_ = [x**2 for x in my_list]

# same thing can be done using a generator expression
# generator expressions are surrounded by parenthesis ()
generator = (x**2 for x in my_list)

print(list_)
print(generator)

输出

[1, 9, 36, 100]
<generator object <genexpr> at 0x7f5d4eb4bf50>

我们可以在上面看到生成器表达式没有立即产生所需的结果。相反,它返回了一个生成器对象,该对象仅按需生成项目。

下面是我们如何开始从生成器中获取项目:

# Initialize the list
my_list = [1, 3, 6, 10]

a = (x**2 for x in my_list)
print(next(a))

print(next(a))

print(next(a))

print(next(a))

next(a)

当我们运行上面的程序时,我们得到如下输出:

1
9
36
100
Traceback (most recent call last):
  File "<string>", line 15, in <module>
StopIteration

生成器表达式可以用作函数参数。这样使用时,圆括号可以去掉。

>>> sum(x**2 for x in my_list)
146

>>> max(x**2 for x in my_list)
100

Python 生成器的使用

有几个原因使生成器成为强大的实现。

1。易于实施

与迭代器类对应物相比,生成器可以以清晰简洁的方式实现。以下是使用迭代器类实现 2 次幂序列的示例。

class PowTwo:
    def __init__(self, max=0):
        self.n = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        if self.n > self.max:
            raise StopIteration

        result = 2 ** self.n
        self.n += 1
        return result

上述程序冗长且令人困惑。现在,让我们使用生成器函数来做同样的事情。

def PowTwoGen(max=0):
    n = 0
    while n < max:
        yield 2 ** n
        n += 1

由于生成器会自动跟踪细节,因此实现更加简洁明了。

2。内存高效

返回序列的普通函数将在返回结果之前在内存中创建整个序列。如果序列中的项目数量非常多,这有点过头了。

这种序列的生成器实现是内存友好的,并且是首选的,因为它一次只生成一个项目。

3。代表无限流

生成器是代表无限数据流的绝佳媒介。无限流不能存储在内存中,由于生成器一次只生成一项,因此它们可以表示无限的数据流。

下面的生成器函数可以生成所有的偶数(至少理论上是这样)。

def all_even():
    n = 0
    while True:
        yield n
        n += 2

4。流水线生成器

多个生成器可用于流水线化一系列操作。最好用一个例子来说明这一点。

假设我们有一个生成斐波那契数列的生成器。我们还有另一个用于平方数字的生成器。

如果我们想找出斐波那契数列的平方和,我们可以通过将生成器函数的输出一起流水线化来实现。

def fibonacci_numbers(nums):
    x, y = 0, 1
    for _ in range(nums):
        x, y = y, x+y
        yield x

def square(nums):
    for num in nums:
        yield num**2

print(sum(square(fibonacci_numbers(10))))

输出

4895

这种流水线高效且易于阅读(是的,更酷!)。


Python

  1. Python 运算符
  2. Python 函数参数
  3. Python字典
  4. Python 生成器
  5. Python 闭包
  6. Python 装饰器
  7. 带有示例的 Python Lambda 函数
  8. Python abs() 函数:绝对值示例
  9. 带有示例的 Python round() 函数
  10. 带有示例的 Python map() 函数
  11. Python 教程中的收益:生成器和收益与返回示例
  12. Python 中的 Enumerate() 函数:循环、元组、字符串(示例)