raring-coffee20
raring-coffee20

Reputation: 300

Python scope between local and global

I have two samples:

One:

import math

def my_function():
    print(math.pi)
    math.pi = 3
    print(math.pi)

my_function()

Output:

3.141592653589793
3

Two:

a = 0

def my_function():
    print(a)
    a = 3
    print(a)

my_function()

Output:

UnboundLocalError: local variable 'a' referenced before assignment

So what is the difference between them? I thought both math.pi and a were global in this case and it should produce UnboundLocalError.

Upvotes: 3

Views: 309

Answers (3)

Christian Will
Christian Will

Reputation: 1695

This has been answered a few times on SO before.

A variable is local to a function if there's a statement assigning it inside that function. In your instance a = 3 defines a as local variable inside of your function. The first print(a) tries to access it, but it's not assigned a value yet.

That's why you see:

UnboundLocalError: local variable 'a' referenced before assignment.

The global instance created by a = 0 plays no role here.

Upvotes: 0

Barmar
Barmar

Reputation: 780673

In the first function, the variable is math, not math.pi. Since you're not assigning to math, it doesn't become a local variable. Assigning to an attribute of a variable is not the same thing as assigning to the variable itself.

If you changed the function to

def my_function():
    print(math.pi)
    math = 3
    print(math.pi)

you would get the same kind of error as in the second function:

UnboundLocalError: local variable 'math' referenced before assignment

Upvotes: 1

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22021

If you do variable assignment within function the global variable would be ignored and won't be accessible within function execution, in sample with math lib you do not override name math itself, that's why it works. Snipped below would give you same error with math lib:

import math

def my_function():
  print(math.pi)
  math = 1

my_function()

You can use statement global before accessing variable, but if you will do any assignment later you will override global variable, so it's better to ALWAYS avoid doing that.

import math


def my_function():
  global math
  print(math.pi)
  math = 1

print(math) # -> <module 'math' from ...    
my_function() # -> 3.14159265359
print(math) # -> 1

Upvotes: 4

Related Questions