Edward Snowden
Edward Snowden

Reputation: 29

Python showing local variable referenced before assignment

I've declared 2 variables the same exact way, but when I'm calling them stack is being referenced fine. But python is not able to reference top. What is the issue here?

def isValid(s):
    top=-1
    stack=[-1]*10005

    def push(x):
        print(top)
        top+=1
        stack[top]=x
    push()

print(isValid(input()))

Upvotes: 2

Views: 1402

Answers (4)

N Djel Okoye
N Djel Okoye

Reputation: 1080

top is pointing to a literal hence it is immutable and stack is a mutable object if you wanted to solve the problem with top which is not actually a problem, you have 2 options.

  1. create a copy of top in push
  2. use a mutable object

example:

  1. nonlocal top
  2. top = {'value': -1 }

case: 1

def isValid(s):
top=-1
stack=[-1]*10005

def push(x):
    nonlocal top
    print(top)
    top+=1
    stack[top]=x

case 2:

def isValid(s):
    top= {'value': -1}
    stack=[-1]*10005

def push(x):
    print(top)
    top['value']+=1
    stack[top]=x

Upvotes: 0

Grismar
Grismar

Reputation: 31319

The difference lies in how you access the variable, which causes it to be treated differently. Consider this:

def isValid():
    top = -1

    def push():
        print(top)

    push()


isValid()

Here there is no error, since top can be found in the scope of isValid() and calling push() will print it correctly. However, if you add top += 1, Python correctly infers that top apparently has to be a local variable for that to work, but it isn't, so now top is showing as problematic everywhere inside push() (in most IDEs).

def isValid():
    top = -1

    def push():
        print(top)  # you'll see error messages / highlighting for top here
        top += 1  # and here as well

    push()


isValid()

Note that top += 1 isn't even the first statement, but its presence causes print(top) to no longer work either, since top now has to be local. But since there's no assignment to top before the other two statements, Python will correctly complain that it has been accessed before having been assigned.

The reason this doesn't happen with your stack is that you're not actually trying to change stack inside push(). You're trying to change one of its elements (stack[1]), but that doesn't change what object stack is naming - you're not assigning to stack itself, so it does not become local.

So, Python finds stack in the scope of isValid, allows you to access it (just like top in the first example) and you can access its elements without issue.

Upvotes: 0

Frank Yellin
Frank Yellin

Reputation: 11240

The previous answer is mostly correct. Python considers any variable that you directly change the value of to be a local variable. Since you write top += 1, top is directly modified inside push, and is a local variable to push. The variable stack, on the other hand, is not changed.

I consider the fact that Python considers += operators to cause a variable to become local to be a bit of a bug. But it's too ingrained in the language.

And yes, the correct solution is to use nonlocal.

If you removed the top += 1 line, your code wouldn't work, but top would refer to the outer variable.

Upvotes: 1

enzo
enzo

Reputation: 11486

Because push is indented inside isValid, it can't change the value of top from its "parent" function.

You can use nonlocal:

def isValid(s):
    top=-1
    stack=[-1]*10005

    def push(x):
        nonlocal top
        print(top)
        top+=1
        stack[top]=x

Upvotes: 0

Related Questions