Quote:True, but Python's structure is such, no?
No, python does not do what you claim. Variables are not "lost".
I think you may be confused about scope.
A variable in a function only exists within the scope of the function. You cannot access the variable from outside the function. Remember Pedroski55 mentioning LEGB? L (local) can see EGB, but EGB cannot see into L. For example:
def counter(end):
start = 0
while start < end:
yield start
start += 1
iter = counter(10)
print(next(iter))
try:
print(start)
except NameError as ex:
print(ex)
try:
print(counter.start)
except AttributeError as ex:
print(ex)
print(next(iter))
Output:
0
name 'start' is not defined
'function' object has no attribute 'start'
1
When I try to use the variable "start" from outside the counter() function, python tells me that there is not a variable named "start". This does not mean there is no variable named "start", it means that there is no variable named "start" in any scope that is visible to my print statements. There is obviously a variable named "start" inside the counter() function, and that variable obviously still exists somewhere, because when I ask for the next value from counter() it returns 1. counter() remembers "start", and "start" still exists. We just can't see "start" from outside counter().
Someone ignorant of how scope works might try to get access to "start" inside of counter() like this:
start = None
def counter(end):
start = 0
while start < end:
yield start
start += 1
iter = counter(10)
print(next(iter))
print(start)
print(next(iter))
print(start)
print(next(iter))
Output:
0
None
1
None
2
Now we have two variables named "start": one in the scope of the module and one in the scope of the function. The variables have the same name, but are not related in any way. This is a desirable outcome because it provides encapsulation. You can change the name of the variables inside counter() without any concern of that affecting code outside of counter(). Encapsulation is a good thing, remember? We really don't want to look at variables inside a function because code that does that is dependent on the implementation of the function, not just the interface. Any change to the function would require searching all code for any references to function internals.
To get a variable value from a function, the function uses return or yield. return returns a value and exits the function. yield returns a value but does not exit the function. Functions that use yield are called "generators". counter() is a generator.
def counter(end):
start = 0
while start < end:
yield start
start += 1
iter = counter(10)
a = next(iter)
b = next(iter)
c = next(iter)
print(a, b, c)
Output:
0 1 2
variables in the module scope, a, b and c, are used to reference the value returned by the counter function/generator. Notice that the values are not "lost". Things are only "lost" when they are not referenced anywhere in the program. If there are no references to something you cannot use it, so Python deletes the object and recycles the memory.