看到别人代码:
<code>def mongoGridfsFiles(): ... client = MongoClient(uri) db = client.gridfs collection = db.fs.files for document in collection.find(): yield document </code>
def main():
db = pymysql.connect(**curMysqlConfigDict)
documents = mongoGridfsFiles()
insertMedia(db, documents)
不太清楚:
为何没有直接用return返回整个数组,而要用yield
且在调试期间注意到:
mongoGridfsFiles没有先执行,而是在后续函数insertMedia中调用到了返回的每个document后,mongoGridfsFiles才执行,才开始产生一个个document并返回
搜:
python return vs yield
When to use yield instead of return in Python? – GeeksforGeeks
3. (译)Python关键字yield的解释(stackoverflow) — 一起写Python文章,一起看Python文章
What is the difference between yield and return in python? – Quora
Python 中的黑暗角落(一):理解 yield 关键字 | 始终
python – What does the “yield” keyword do? – Stack Overflow
想要理解yield,需要先理解generators
以及先要搞清楚:iterables
<code>>>> mylist = [1, 2, 3] >>> for i in mylist: ... print(i) 1 2 3 </code>
以及:
<code>>>> mylist = [x*x for x in range(3)] >>> for i in mylist: ... print(i) 0 1 4 </code>
类似的这种iterable的,比如
lists, strings, files…
等等,缺点是:
所有的值,都要保存到内存中
-》而实际情况下,当数据个数很多时,数据量很大时,我们并不希望所有的值都作为list返回,都放在内存中
Generators是个iterators,是其中一种iterable,你可以每次循环只返回一个值
Generators并不把所有的值都保存在内存中 -》 是实时的,在你用的时候,才产生,生成对应的值:
<code>>>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4 </code>
注意到此处是(),表示Generator
(之前的[],表示list)
不过Generator没法被(第二次)多次调用,即此处不能再次调用:
for i in mygenerator:
yield
yield,使用方式和return差不多
除了函数本身会返回一个generator
<code>>>> def createGenerator(): ... mylist = range(3) ... for i in mylist: ... yield i*i ... >>> mygenerator = createGenerator() # create a generator >>> print(mygenerator) # mygenerator is an object! <generator object createGenerator at 0xb7555c34> >>> for i in mygenerator: ... print(i) 0 1 4 </code>
此处去调试代码,发现的确函数mongoDialogs返回的的确是generator的object:
<code><generator object mongoDialogs at 0x10698dd00> </code>
所以,此处通过函数中用yield返回一个generator,满足了如下场景:
确定会返回大量的,很多个的数据
且不希望占用内存
否则直接return返回数据的list,数据量太大,会占用太多内存
且确保只会使用一次
generator只有一条命 -》generator只能用一次,第二次再去调用就无效了
注意:直接调用对应包含了yield的函数时,函数是不会执行的,直到你后期使用到了该(函数返回的)generator时,函数才会真正执行
逻辑是,感觉有点点像是delay的逻辑,延迟加载/执行
然后对于后续回复中,有人说的更清楚:
yield没有看起来的那么魔性。
其内部执行逻辑是:
你调用了包含yield的函数时,函数代码没有被执行,只是返回一个generator对象。
当后续你使用generator,去获取一个值时,python解析器才,第一次的,真正的去执行对应的代码,知道碰到第一个yield,返回你要的第一个值,然后暂停该函数的执行(等待下次继续被调用)
后续要返回第二个值时,python解析器再去继续恢复执行yield部分,返回第二个值,再暂停执行;
如此继续。
直到返回所有的值。
此时generator本身也就被消耗殆尽,彻底消失了。
如此而已。
也因此,generator只有一条命,无法被多次重复调用。
【总结】
正常的,小批量的数据,直接用普通的list等类型,即可
list等类型的数据是保存在内存中的
如果满足如下场景
确定会返回大量的,很多个的数据
且不希望占用太多内存
且确保只会使用一次
generator只有一条命 -》generator只能用一次,第二次再去调用就无效了
举例:
比如我此处mongo中dialog有4万多个
如果全部一次性返回成list列表,则会消耗大量内存
且确保只会调用一次generator,用完就无需再用了
再去使用yield:
且确保你了解yield的内部工作逻辑
注意事项:直接调用对应包含了yield的函数时,函数是不会执行的
直到你后期使用到了该(函数返回的)generator时,函数才会真正执行
感觉逻辑点像是delay的逻辑,延迟加载/执行
转载请注明:在路上 » 【已解决】Python中直接return数组和yield的区别