views:

108

answers:

5

Hi all,
I'm currently developing some things in Python and I have a question about variables scope.

This is the code:

a = None
anything = False
if anything:
    a = 1
else:
    a = 2

print a # prints 2

If I remove the first line (a = None) the code still works as before. However in this case I'd be declaring the variable inside an "if" block, and regarding other languages like Java, that variable would only be visible inside the "if".

How exactly variable scoping works in Python and what's the good way to program in cases like this?

Thanks!

+2  A: 

I believe that Python uses function scope for local variables. That is, in any given function, if you assign a value to a local variable, it will be available from that moment onwards within that function until it returns. Therefore, since both branches of your code are guaranteed to assign to a, there is no need to assign None to a initially.

Note that when you can also access variables declared in outer functions -- in other words, Python has closures.

def adder(first):
    def add(second):
        return first + second

    return add

This defines a function called adder. When called with an argument first, it will return a function that adds whatever argument it receives to first and return that value. For instance:

add_two = adder(2)
add_three = adder(3)
add_two(4) # = 6
add_three(4) # = 7

However, although you can read the value from the outer function, you can't change it (unlike in many other languages). For instance, imagine trying to implement an accumulator. You might write code like so:

def accumulator():
    total = 0
    def add(number):
        total += number
        return total
    return add

Unfortunately, trying to use this code results in an error message:

UnboundLocalError: local variable 'total' referenced before assignment

This is because the line total += number tries to change the value of total, which cannot be done in this way in Python.

Michael Williamson
You can do what you need in your `accumulator()` example by using `nonlocal` (new in Python 3).
Greg Hewgill
A: 

Python doesn't need variables to be declared initially, so you can declare and define at arbitrary points. And yes, the scope is function scope, so it will be visible outside the if.

Skilldrick
+6  A: 

As a rule of thumb, scopes are created in three places:

  1. File-scope - otherwise known as module scope
  2. Class-scope - created inside class blocks
  3. Function-scope - created inside def blocks

(There are a few exceptions to these.)

Assigning to a name reserves it in the scope namespace, marked as unbound until reaching the first assignment. So for a mental model, you are assigning values to names in a scope.

Shane Holloway
There are actually four places, the fourth being Global scope. But this really depends on whether you consider global to be a scope in itself.
jathanism
As far as I understand global scope, it is generally synonymous with file/module scope. The exceptions I know about involve passing a dictionary for globals into `exec` or `eval`. From memory, the fourth scope is found in generator expressions, not allowing iterator variables to escape. And the fifth is non-local block scope for closures -- I've never found an easy way to explain that one.
Shane Holloway
+1 Nice answer.
cjrh
+1  A: 

There is no problem assigning the variable in the if block.

In this case it is being assigned on both branches, so you can see it will definitely be defined when you come to print it.

If one of the branches did not assign to a then a NameError exception would be raise when you try to print it after that branch

gnibbler
A: 

hello, i'm quite a beginner programmer, but for what i know, in python private variables don't exist. see private variables in the python documentation for a detailed discussion.

useful informations can also be found in the section "scopes and namespaces" on the same page.

personally, i write code like the one you posted pretty much every day, especially when the condition relies in getting input from the user, for example

if len(sys.argv)==2:
    f = open(sys.argv[1], 'r')
else:
    print ('provide input file')

i do declare variables before using them for structured types, for example i declare an empty list before appending its items within a loop.

hope it helps.

japs