使用产量的函数有多少内存?

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
Run Code Online (Sandbox Code Playgroud)

如果我迭代第一个函数返回的生成器,那么巨大的范围是否实际存储在内存中?

第二个功能怎么样?

如果我迭代第三个函数返回的生成器,那么我的程序会使用更少的内存(而不是仅仅创建该字典并直接迭代它)吗?

Mar*_*ers 5

Python 2 range()函数生成的巨大列表需要存储,是的,并将占用内存,在生成器函数的整个生命周期内.

发电机的功能可以是内存使用效率,提供其生产需要的计算结果,但range()函数生成所有结果前面.

你可以计算下一个数字:

def function1():
    i = 0
    while i < HUGE_NUMBER:
        yield i
        i += 1
Run Code Online (Sandbox Code Playgroud)

并且你会得到相同的结果,但你不会一次性存储整个范围的所有数字.这基本上是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
Run Code Online (Sandbox Code Playgroud)

这只存储了可以避免重复的密钥(就像字典一样)但是没有存储值.迭代生成器时内存会增加.如果重复项不是问题,您可以省略完全跟踪看到的键:

def function3(file):
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        for k, v in reader:
            yield k, v
Run Code Online (Sandbox Code Playgroud)

甚至

def function3(file):
    with open(file, 'r') as f:
        reader = csv.reader(f, delimiter = ' ')
        return reader
Run Code Online (Sandbox Code Playgroud)

毕竟,读者是可迭代的.