Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

State information and immutability of lists in Python

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.

like image 930
watchtower Avatar asked Mar 11 '26 11:03

watchtower


1 Answers

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
like image 178
Patrick Haugh Avatar answered Mar 13 '26 01:03

Patrick Haugh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!