iCa*_*arn 3 python memory yield generator
我无法理解yield关键字.
我理解程序执行时会发生什么影响,但我真的不明白它使用了多少内存.
我将尝试用例子来解释我的怀疑.
假设我们有三个功能:
HUGE_NUMBER = 9223372036854775807
def function1():
    for i in range(0, HUGE_NUMBER):
        yield i
def function2():
    x = range(0, HUGE_NUMBER)
    for i in x:
        yield i
def function3(file):
    with open(file, 'r') as f:
        dictionary = dict(csv.reader(f, delimiter = ' '))
    for k,v in dictionary.iteritems():
        yield k,v
如果我迭代第一个函数返回的生成器,那么巨大的范围是否实际存储在内存中?
第二个功能怎么样?
如果我迭代第三个函数返回的生成器,那么我的程序会使用更少的内存(而不是仅仅创建该字典并直接迭代它)吗?
Python 2 range()函数生成的巨大列表需要存储,是的,并将占用内存,在生成器函数的整个生命周期内.
发电机的功能可以是内存使用效率,提供其生产需要的计算结果,但range()函数生成所有结果前面.
你可以计算下一个数字:
def function1():
    i = 0
    while i < HUGE_NUMBER:
        yield i
        i += 1
并且你会得到相同的结果,但你不会一次性存储整个范围的所有数字.这基本上是xrange()对象的循环; 它根据要求计算数字.(在Python 3中xrange()取代range()).
这同样适用于您function3; 您首先将整个文件读入字典,以便在迭代时仍然存储在内存中.之后不需要将整个文件读入内存中以生成每个元素.你可以循环遍历文件并产生线:
def function3(file):
    seen = set()
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        for k, v in reader:
            if k in seen:
                # already seen
                continue
            seen.add(k)
            yield k, v
这只存储了可以避免重复的密钥(就像字典一样)但是没有存储值.迭代生成器时内存会增加.如果重复项不是问题,您可以省略完全跟踪看到的键:
def function3(file):
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        for k, v in reader:
            yield k, v
甚至
def function3(file):
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        return reader
毕竟,读者是可迭代的.