Jose：大家好,
欢迎回来, 在这段视频中, 我们将讨论Python中的生成器｡
我对这一节感到非常兴奋,
因为我们将讨论一些更高级的东西, 生成器是Python中的一个主题, 很多课程甚至没有提到,
但它们对性能是必不可少的, 还因为Python中的e-sync开发, 我们稍后将学习的e-sync开发, 是建立在这些生成器之上的｡
当你理解了生成器, Python中的很多东西就会变得更加清晰｡
那么什么是发电机呢？
Python中的生成器是一个函数｡
这是一个特殊的功能｡
看一个函数, 它会记住它在两次执行之间的状态, 这样你就可以多次运行这个函数,
它会记住你上次运行它时它做了什么｡
这听起来很奇怪, 让我用一个例子来解释｡
假设你想建立一个包含100个数字的列表,
非常简单, 你想得到一个包含从0到99的数字的新列表, 不包括100｡
所以你可以做一个像这样的函数｡
显然没有使用范围等, 你知道范围｡
让我们不要使用range, 而是从头开始构建一个列表｡
你会怎么做｡
一个好的方法是从一个空列表开始｡
我们称之为nums, 并使其等于一个空列表｡
并且也从等于零的索引开始｡
然后当i小于100时, 说nums
dot append i｡
所以你要在开头加上零｡
然后把i加1, 等于1.
你要加1, 重复,
加2, 然后加3, 以此类推, 直到加到99.
在这个函数的最后,
返回nums, 这是你的数字列表｡
如果我们打印出一百个数字, 然后运行它｡
我们可以看到它包含了一百个数字的列表｡
当然, 我们可以使用列表解析来实现这一点｡
我们可以使用范围函数, 但现在我们假设这是一个很酷的方法,
因为我真正要解释的是范围函数在内部是如何工作的｡
所以我们构造一个列表, 用前一百个数字填充它, 然后返回｡
现在我们有一百个数字在一个列表中｡
这整个列表在您的计算机内存中存储为函数的返回值｡
100个数字并不是很大, 它占用的空间很小, 但是假设我们要存储1000万个数字,
1000万个数字就像100个数字, 但是它可能是100万个数字｡
你会生成一个一百万个数字的列表, 并把它存储在这个变量中,
这个变量会进入你的计算机内存, 它可能会占用更大的内存, 因为这些数字中的每一个都占用了你的计算机内存的一小部分｡
如果你想要1000万个数字, 那么它更大, 所以｡
现在有1000万个数字不是一个很好的例子, 但是想象一下你有一个很长的列表｡
例如, 这些经常被用于计算质数, 在大数据和类似的事情中,
你可能有时会想要一个大列表｡
所以我们用一个生成器来解决这个问题, 因为假设你不需要一次有100个数字｡
你需要的是零, 这样你就可以用它做一些事情｡
然后一个这样你就可以用它做点什么了｡
然后是两个这样你就可以用它做点什么了｡
例如,
对于这100个数字, 我们可以把它们都乘以2, 然后把它们存储在另一个列表中｡
你会怎么做？
你会做一些类似于较少理解的事情,
x乘以2, 得到x的100个数字｡
你要做的就是用这个列表来分离, 然后把每个数字乘以2.
让我们把这个乘以2的运算看作是我们想要对这些数字进行的运算, 以便计算出一些东西｡
另一个例子是, 如果你有很多用户, 你想计算他们周围的参与度,
或者他们对你的系统的参与度, 或者类似的东西｡
实际上, 您需要检查每个元素并执行一个操作｡
这里的问题是, 你不需要所有的元素在一次｡
你需要他们一个接一个｡
这就是发电机的用途｡
生成器给出的不是整个元素列表, 而是列表中的第一个元素,
而不是把所有的元素都存储在内存中.
下一次调用生成器时, 它会记住上次给你的元素,
并知道要给予你第二个元素｡
然后你再运行一次, 它会给你第三个元素, 依此类推｡
它永远不会将列表存储在内存中, 它总是只记住它给你的最后一个数字, 这样它就可以给予你下一个数字｡
每次你想要一个新的数字时, 你都必须给这个函数赋值, 这就是为什么它被称为生成器,
因为它生成数字,
或者字符串, 或者用户, 或者任何你想生成的东西.
你应该这样做, 而不是“数字“｡
append（i）", 你说“yield
i”,
因为i是我们要返回的数字, 我们不再需要这个nums
equal方括号, 也不再需要return段｡
所以这个函数叫做生成器函数｡
收益率和收益率很像,
但当你调用它的时候它会给出i, 然后它会记得它在这里, 它停在第5行之前｡
就在中间的第四行后面｡
下一次你调用这个函数时, 它会继续,
它会把i加1, 它会重新运行循环, 得到1,
给予你1然后停止.
下次你调用它的时候, 它会继续递增i买一,
重复这个循环, 然后给予你两个, 然后它会停止, 依此类推｡
最后当你用完了数字, 它将不会产生任何结果｡
然后你就知道一切都结束了｡
那我们要怎么做
让我们首先打印出一百个数字｡
注意它不再给我们一个列表, 现在它给了我们一个生成器对象, 叫做bundred
numbers, 这就是我们函数的名字｡
它还为我们提供对象的内存地址｡
注意我们是如何定义函数的, 但是print告诉我们这是一个对象,
因为Python在后台意识到你已经使用了yield, 你正在创建一个生成器, 然后它把它们变成了一个python对象｡
稍后我将告诉你如何在没有函数的情况下自己创建这些对象｡
因此, 让我们将生成器存储在一个变量中｡
我们叫它“g,
”这是一个很流行的名字, 在一个小程序中用来表示生成器｡
如果你有很多生成器, 当然你必须选择一个更具描述性的名字｡
然后打印生成器给予出的下一个值｡
注意, 当你初始化一个生成器时, 像这样,
它不运行函数, 它从最顶部开始,
根本不运行｡
当你问它下一个值时,
它会一直运行到收益, 然后给予你你已经产生的任何值｡
你问它下一个值的方式, 是你不再运行这个函数, 而是说下一个g.
接下来是一个内置的函数, 它会影响发电机,
它会告诉发电机增加到发电量｡
好的, 如果我们运行这个, 你可以看到现在我们得到了零,
因为这是产生的第一个数字｡
现在我们的发电机, “g”, 停在了4号线这里｡
如果我们问它另一个数, 注意到, 在程序结束时,
发生器被破坏了, 所以如果我们再运行一次这个程序, 它会再次是0,
现在是1｡
它不会在程序执行过程中记住它, 这不是Python的工作方式｡
所以现在我们可以问它第一个数字, 然后问下一个数字｡
在第一个数字之后, 它会在4到5之间停止｡
当我们说next的时候,
它会一直持续到下一个yield, 这意味着重复这个循环一次, 得到一个｡
好吧, 我会的
非常重要的是, 函数记住了它停止的位置｡
所以在任何时候,
你都可以停止函数的运行, 然后你可以调用next来继续它｡
所以, 它不仅对生成数字有用,
当你想暂时停止一个函数运行时, 它也很有用, 然后你可以随时继续运行它,
通过调用next.
所以,
这可能不是什么有意义的事情, 但只要记住,
当我们需要它, 当我们做一个同步编程｡
那么范围函数呢？
我之前说过这基本上解释了值域函数是如何在内部工作的, 这是真的,
但是值域函数并没有直接给予你一个生成器｡
这里,
让我们做一些像“我的范围对象”, 它将是范围10｡
它的行为非常像一个生成器, 但是如果你调用“my range
object”的next,
你会得到一个错误, 看看这个｡
这是因为range对象并不是一个生成器,
即使它是这样的, 它并不生成一个列表,
然后允许你迭代它, 它以这种类似于生成的方式工作, 以提高效率｡
“我的范围对象, ”你们还记得我们在课程的早期打印出来了,
我们收到了一些奇怪的0到10范围的东西｡
这只是调用了“repr”函数,
你可以看到, 如果我们打印出“repr”的结果, 我们还可以看到0到10的范围｡
我的range对象的行为很像这样,
我们会在几个视频中学习, 如何迭代一个对象, 使其行为像一个range对象｡
我们已经学习了这些生成器, 还有一件事我想提一下, 关于生成器,
列表函数可以把生成器变成列表｡
这样我们就可以打印“g”的列表了｡
就在这里, 我们称之为“下一个”, 然后又是“下一个”,
然后是“列表”｡
所以现在我们打印出了0和1,
这是我们的下一个函数中的两个东西, 然后我们生成了一个生成器的列表, 但是这个列表当然会从我们离开的地方继续｡
生成器自己会记住它是什么,
所以列表从2开始, 而不是从0开始｡
所以, 在发电机中记住这一点非常重要,
他们记得自己在哪里｡
所以, 当你创建一个时, 从你开始使用它的那一刻起, 从你开始在它上面调用“下一个”的那一刻起, 它就记住了它在哪里,
你不能后退｡
好吧, 我会的
在接下来的几个视频中, 我们将学习更多关于发电机的知识｡
我们将学习生成器类,
如何创建一个行为类似生成器的类, 我们还将学习Python中的迭代器和可迭代对象, range目标就是一个这样的例子｡
然后,
我们将转到一些函数式编程示例, 如filter､
map､ any and all和enumerate｡
所以, 对于这一节, 我非常兴奋,
我相信,
生成器将是你在Python开发中需要的东西, 特别是在我们继续学习课程的时候｡
所以说, 我会看到你在下一个视频｡