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.

surya singh
  • 450
  • 2
  • 12

1 Answers1

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).

Alfe
  • 56,346
  • 20
  • 107
  • 159
  • 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. – surya singh Oct 05 '17 at 08:40
  • I don't understand. If you have an assignment in the function anywhere, then every access and assignment will be compiled to accessing a local variable. If at runtime an assignment takes place, the dict will be extended accordingly. If access is done before the assignment, the dict will lack the entry and this will raise the exception. – Alfe Oct 05 '17 at 08:48
  • I want to know that python will look somewhere if that variable has assignment in function. As i know python look inside `locals()` first to check if that variable is in local namespace, thn `globals()` for global namespace. so in which variable python look for this case. – surya singh Oct 05 '17 at 08:56
  • 1
    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. – Alfe Oct 05 '17 at 09:45
  • 1
    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. – Alfe Oct 05 '17 at 09:48
  • Okay I understand, that variable is considered as local at compile time. I want to know where python store that information. I am sorry, I am not able to tell you what exactly I want to ask. I appreciate your time. – surya singh Oct 05 '17 at 10:04
  • 1
    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. – Alfe Oct 06 '17 at 07:32
  • I checked this again. If you try to access a local variable which isn't set yet, you will get an `UnboundLocalError` (which inherits `NameError`). If you try to access a global variable which isn't set yet, you will get a pure `NameError`. So to distinguish between the two you can use `isinstance(e, UnboundLocalError)` (or `except` this class of course). And just in case you don't know yet, please accept an answer if it solves your issue (press the check mark left to the answer). You can also upvote otherwise helpful answers (with the upward triangle left to the answer). – Alfe Oct 10 '17 at 10:14
  • 1
    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. https://docs.python.org/2.7/tutorial/classes.html#python-scopes-and-namespaces make it more clear for me. – surya singh Oct 10 '17 at 10:42