I am a beginner in Python and using Mark Lutz's book to learn the fundamentals of Python.
Here's an example that the author uses to demonstrate storing state information using lists:
def tester(start):
def nested(label):
print(label,state[0])
state[0] += 1
state = [start]
return nested
Here's the code to test state information:
F = tester(3)
F('sam')
F('sam')
You would see that the counter increases from 3 and then continues. In essence, above code stores initial state start
(passed during initialization of the object) in [state]
and increments it every time label
is called.
However, I am unsure why Python doesn't throw an error in nested
block. Specifically, [state]
is local to tester
and not nested.
To demonstrate what I mean, I am going to replace state[0]
by state.
def tester(start):
def nested(label):
print(label,state) #Replaced state[0] with state
state += 1 #Replaced state[0] with state
print("after:",state)
state = start #Replaced state[0] with state
return nested
Technically, above code should also work fine because all I have done is that replaced the list with the variable. However, PyCharm wouldn't even run this code. I get an error nboundLocalError: local variable 'state' referenced before assignment
Can someone please explain why the version with list
works fine? The author has stated that "this leverages the mutability of lists, and relies on the fact that in-place object do not classify a name as local."
I am not really sure what that means. Can someone please help me? Thanks for any help extended to me.
You should read this section of the documentation.
Basically, in both versions the scope of the nested block allows it to interact with the namespace of the encompassing block. The difference is that you are not reassigning state
in the first example, you're mutating it.
In the second example, Python knows that you are going to assign a value to that reference later in the function, so it is treated as a name from the local nested
namespace, rather than the outer tester
namespace.
You can use the nonlocal
keyword to circumvent this and use the other reference from the other namespace
def tester(start):
def nested(label):
nonlocal state
print(label,state)
state += 1
print("after:",state)
state = start
return nested