1

I looking some explanations with Namespace concept in functions.

Here is a code which will raise UnboundLocalError: local variable … referenced before assignment

x = 1
def foo():
    print x
    x = 2

I Understand this should raise exception. But I want to understand how python know that is variable is in local namespace. At line print x, x is not in local variable dict.

x = 1
def foo():
    print 'local before print x : ',locals()
    print x
    print 'local after print x :',locals()
    x = 2

foo() # call function, print local namespace before raising exception
local before print x :  {}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
UnboundLocalError: local variable 'x' referenced before assignment

Before print x, local namespace dict is empty {}(which is very obvious). So how does python know that x is local variable.

This works differently with classes

a = [1]
class b():
    c = a
    a = 2

print 'c inside class ', b.c
'c inside class  [1]'

d = b()

No Exception is raised with similar case in class.

If someone can help me explaining concept, how python knows before assignment that this variable is local variable.

I have checked many forms and sites for explanation but didn't find any.

There are post and forms which explain how to solve this case. example. UnboundLocalError: local variable … referenced before assignment . But I am looking for python working behind.

1 Answer 1

1

Python precompiles your code into some bytecode. In this step it will find out for each scope (function, typically) whether an identifier references a global or a local variable.

  • If it is declared as global explicitly, it is global (easy case).
  • If a value is assigned to it anywhere in the function without being declared global explicitly, it is local.
  • If it is only read in the function, it is assumed to be global (implicitly).

This is done at compile time, so nothing is executed to determine this.

Now, at runtime, if you read a local variable before assigning it, you get your error.

Now, with classes you have a different situation because the variables there aren't really local (i. e located on the memory of the call stack). If you access a in a declaration of b you will access the module-global variable unless a class-global variable exists which overrides the module-global one. If you assign to a, you will create (or change) a class-global variable. Any subsequent access of a (or assignment to) will access the class-global one (or assign to).

Sign up to request clarification or add additional context in comments.

9 Comments

Yes I completely agree with you. But when I print locals() before printing that variable it gives empty dict. So where does python look for local variable if not in locals.
It won't look into both. It will look into locals() if the compile step found out that it should be a local variable (using the determinism sketched above). It will look into globals() if the variable was determined at compile time to be a global one. If it doesn't find it there, the exception is thrown. There is no "fallback" to globals() if it isn't found in locals() or vice versa.
All that is true for functions which can have local variables. For classes, you have a different concept; there are no "local" variables but class-global ones (as apposed to module-global ones). In this case, you have the fallback and override mechanism (first class-global variables and subsiding the module-global ones) you wrongly assumed to have at functions with locals and globals.
That information is stored in the produced bytecode. It either will contain code for accessing the local variables on the stack or for accessing the global variables. Which makes it hard to "find out" during runtime (if this is your goal, I'm not sure about your usecase, but it sounds a bit like it this). You could access the variable in a try clase and check the error in case it isn't available. The message probably differs for local and global variables.
I did not accept it because your answer was not what exactly i was looking for. It gets clear from your comments. thats why i vote useful on your comments. docs.python.org/2.7/tutorial/… make it more clear for me.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.