为了更好地理解关键字yield
的用法,首先需要理解迭代器(iterator)与生成器(generator)的区别。当创建列表中的元素时,我们可以使用for
循环:
>>> myIterator = [x*x for x in range(3)]
>>> print(myIterator)
[0, 1, 4]
因此我们称列表是可迭代的(iterable)。但是基于这种方法逐次访问列表中的元素时,需要首先将包含所有元素的列表创建并保存,当元素数量过多时可能造成内存空间的利用效率下降。因此考虑只进行一次迭代的生成器,并不在访问元素之前将所有元素值存储在内存空间,而是在迭代过程中生成要访问的元素,并且访问过的元素就不会再存储在生成器所占的内存空间中。
>>> myGenerator = (x*x for x in range(3))
>>> print(myGenerator)
at 0x000001F67D449518>
>>> for i in myGenerator:
print(i)
0
1
4
>>> print(myGenerator)
at 0x000001F67D449518>
>>> for i in myGenerator:
print(i)
>>>
上述代码首先创建生成器对象,使用for
循环迭代访问生成器中的每一个元素时,可以看到进行一次迭代后生成器就变为空。也可以将生成器对象转换为列表对象,生成器在访问一次之后变为空就可以更明显地看出来:
>>> myGenerator = (x*x for x in range(3))
>>> print(myGenerator)
at 0x000001B3A48DED00>
>>> print(list(myGenerator))
[0, 1, 4]
>>> print(list(myGenerator))
[]
而关键字yield
的作用类似于return
,但返回的是一个生成器对象,注意代码示例表示返回的生成器的元素为i*i
:
>>> def createGenerator():
for i in range(3):
yield i*i
>>> mygenerator = createGenerator()
>>> print(mygenerator)
>>> for item in mygenerator:
print(item)
0
1
4
>>>
在nlp相关应用中,可能在读取数据集时会使用到yield
关键字以节省内存开销,代码示例表示返回的生成器中的元素是列表:
>>> def read_dataset(file):
for line in file:
yield [word for word in line.split(" ")]
>>> dataset = ["hello world", "i love china", "are you ok"]
>>> train = read_dataset(dataset)
>>> print(train)
>>> print(list(train))
[['hello', 'world'], ['i', 'love', 'china'], ['are', 'you', 'ok']]
>>> print(list(train))
[]