Where are the "elements" stored in the generator?

The code below summarizes all the numbers in the list contained in all_numbers. This makes sense, since all the numbers to be added are stored in a list.

def firstn(n):
    '''Returns list number range from 0 to n '''
    num, nums = 0, []
    while num < n:
        nums.append(num)
        num += 1
    return nums

# all numbers are held in a list which is memory intensive
all_numbers = firstn(100000000)
sum_of_first_n = sum(all_numbers)

# Uses 3.8Gb during processing and 1.9Gb to store variables
# 13.9 seconds to process
sum_of_first_n 

When converting the above function into a generator function, I believe that I get the same result with less memory (below code). I don’t understand how all_numbers can be summed if it does not contain all the numbers in the list, as mentioned above?

If numbers are generated on demand, then you would have to generate all numbers to sum them all together, so where are these numbers stored and how does this translate into reduced memory usage?

def firstn(n):
    num = 0
    while num < n:
        yield num
        num += 1

# all numbers are held in a generator
all_numbers = firstn(100000000)
sum_of_first_n = sum(all_numbers)

# Uses < 100Mb during processing and to store variables
# 9.4 seconds to process
sum_of_first_n

I understand how to create a generator function and why you would like to use them, but I do not understand how they work.

+4
4

A generator , , GENERATE , , , "" , , ; , ..

def firstn(n):
    num = 0
    while num < n:
        yield num
        num += 1

, "" num, , firstn num context till the, `.

+5

, :

def firstn(n):
    num = 0
    while num < n:
        yield num
        print('incrementing num')
        num += 1

gen = firstn(n=10)

a0 = next(gen)
print(a0)      # 0
a1 = next(gen) # incrementing num
print(a1)      # 1
a2 = next(gen) # incrementing num
print(a2)      # 2

return, ( ) , yield ed .

for next .

; .

+1

, , / , , , .

, Python, / locals():

locals(): , . () , .

>>> def firstn(n):
     '''Returns list number range from 0 to n '''
     num, nums = 0, []
     while num < n:
         nums.append(num)
         num += 1
         print(locals())
     return nums
>>> firstn(10)

:

{'nums': [0], 'n': 10, 'num': 1}
{'nums': [0, 1], 'n': 10, 'num': 2}
{'nums': [0, 1, 2], 'n': 10, 'num': 3}
{'nums': [0, 1, 2, 3], 'n': 10, 'num': 4}
{'nums': [0, 1, 2, 3, 4], 'n': 10, 'num': 5}
{'nums': [0, 1, 2, 3, 4, 5], 'n': 10, 'num': 6}
{'nums': [0, 1, 2, 3, 4, 5, 6], 'n': 10, 'num': 7}
{'nums': [0, 1, 2, 3, 4, 5, 6, 7], 'n': 10, 'num': 8}
{'nums': [0, 1, 2, 3, 4, 5, 6, 7, 8], 'n': 10, 'num': 9}
{'nums': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'n': 10, 'num': 10}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

:

>>> def firstn(n):
     num = 0
     while num < n:
         yield num
         num += 1
         print(locals())

>>> list(firstn(10))

:

{'n': 10, 'num': 1}
{'n': 10, 'num': 2}
{'n': 10, 'num': 3}
{'n': 10, 'num': 4}
{'n': 10, 'num': 5}
{'n': 10, 'num': 6}
{'n': 10, 'num': 7}
{'n': 10, 'num': 8}
{'n': 10, 'num': 9}
{'n': 10, 'num': 10}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

, , / ( ) . ( while) .

/ , while, ... .

+1

sum Python, , , :

def sum(iterable, start=0):
    part_sum = start
    for element in iterable:
        part_sum += element
    return part_sum

(, sum, , , .)

sum(all_numbers) , element , part_sum , . , , , , , , 100000000. , , next n num .

0

Source: https://habr.com/ru/post/1679551/


All Articles