7

The following code prints 123:

>>> a = 123
>>> def f():
...     print a
...
>>> f()
123
>>>

But the following fails:

>>> a = 123
>>> def f():
...     print a
...     a = 456
...     print a
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment
>>>

I would have expected this to print:

123
456

What am I missing here?

P.S. I'm using Python 2.6.6 if that matters.

ElenaT
  • 2,600
  • 4
  • 24
  • 41
  • Without a parameter to supply your variable reference to the method, you're going to have to rely on `a` to be declared in the code, before the call to function `f()` just to `print a` in the first place. Side effects abound. – yurisich Dec 30 '11 at 11:43
  • I added a solution to your problem, but usally you just want to avoid writting the close. Just make an intermediary variable and returns the result. – Bite code Dec 30 '11 at 12:11

4 Answers4

8

If a function only reads from a variable, it's assumed to be global. If the function writes to it ever, it's assumed to be local. In your second function, a is written to, so it's assumed to be local. Then the line above (where it's read from) isn't valid.

Here's a link to the Python FAQ: http://docs.python.org/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

  • OK, but isn't Python interpreted? I would expect the print to work then fail when I try the assignment (since I would be assigning to a global variable without the `global` declaration being present). Why does it fail on the print and not the assigment? – ElenaT Dec 30 '11 at 11:10
  • 2
    Python is compiled. It's just it compiles to bytecode, to run over a virtual machine (ie. exactly like Java) – Ricardo Cárdenes Dec 30 '11 at 11:12
  • Python is compiled to byte-code at runtime. When a function is compiled, the compiler determines which names are locals are which globals (and other stuff, like if the function is actually a generator when it contains yield statements). –  Dec 30 '11 at 11:13
  • 1
    No it's not. Create a class and a method, then copy/paste his complete code inside the method. You'll see the same problem. You could not use global from here: it could accidently take a variable from outside the class, when what you want is just the one outside the current scope. – Bite code Dec 30 '11 at 11:19
  • It fails on the print and not the assignment for the same reason that it's possible to get a `SyntaxError` from a faulty function definition without actually attempting to call it. – Karl Knechtel Dec 30 '11 at 12:05
  • As an evidence that `a` is indeed treated as global variable, try `dis.dis(f)` (after importing `dis`). This will print the disassembled & annotated bytecode of your function, where you will see the `LOAD_FAST` instructions which are looking up values for local names (as opposed to `LOAD_GLOBAL` for global names). – Xion Dec 30 '11 at 12:53
  • 1
    @e-satis python 3's `nonlocal` solves exactly this problem, causing the compiler to look for bindings of the name in outer, nonglobal scope – Emmett Butler Jan 16 '13 at 15:25
5

That's becouse Python automatically acts like the variable is global unless you define or try to modify it in function. Try adding global a to your code.

>>> a = 123
>>> def f():
...     global a
...     print a
...     a = 456
...     print a
... 
>>> f()
123
456
>>> a
456

In the first example you did not define and did not modify, so it was a global one. But if you would like to, for example, add 20 to a, you also have to use global a.

Also be aware, that the a in f function is a global and it's value will differ after the run of f function.

If you want to create a local variable, then remember, that declaration always go before the reading, so print a can not be done before a = 456.

EDIT: Ok, while we're talking about closures and dangerous of using global there's other possibility.

>>> a = 123
>>> def f():
...     b = a
...     print b
...     b = 456
...     print b
... 
>>> f()
123
456
>>> a
123
>>> 

Here we use a closure read-only ability to make a copy of a and than modify this copy, without modifing the outside a variable AS LONG AS IT'S INTEGER. Remember, that b keeps a reference to a. If a is, for example, a list and the f operation is like b.append(3), then both a and b will be available and modified outside the scope.

The choice of method is different due to needs.

Gandi
  • 3,522
  • 2
  • 21
  • 31
  • Not it's not. You would have the same problem if you would do the same code within a method. Using global would then be dangerous, you would get the variable ouside of the class if it exists. – Bite code Dec 30 '11 at 11:17
  • Thanks, switching the -1 to a +1 – Bite code Dec 30 '11 at 12:13
  • The "we use a closure read-only [...]" makes no sense here. `b = xxx` makes `b` reference something new, and won't affect `a` in any way, even if you do it in the same scope where `a` is defined. – Ricardo Cárdenes Dec 30 '11 at 16:48
  • Well both of us made a mistake. Me in saying, that this way you won't modify the variable outside the scope. You in saying, that `b` won't affect `a` in any way. That depends on the type of `a`. If you want to check it, simply define `a` as a list `b` as a reference to `a` and then append anything to `b`. After running the function both `a` and `b` will be the same, what means that actually they were affected. `b` is a reference to `a`, not a copy of `a`. – Gandi Jan 02 '12 at 14:13
5

What you are using is named a closure: you take a variable from the outter scope and enclose in a function block.

Your code is perfectly alright, and would work in javascript.

Unfortunatly, in Python, closures are read-only.

And the error is always UnboundLocalError: local variable 'var_name' referenced before assignment which is completly misleading.

En short, this is not you, it's a language limitation combined a bad error message.

EDIT:

I can see several persons here advocating the use of global, which has dangerous side effects: you would get access to variables with the same name several scopes above the current one, which is not what you want with closures.

The solution has been added in Python 3, with the nonlocal keyword which does exactly that: rebind a variable from the outer scope in the inner scope.

There is a way to simulate nonlocal for python 2.x, but really you are better off just just not assign anything to your variable: copy values, return values, modify in place only mutable types and you will be fine.

Bite code
  • 578,959
  • 113
  • 301
  • 329
  • Didn't know closures were read-only. Are there any other limitations to Python closures? Where could I find more info? (on the limitations that is) – ElenaT Dec 30 '11 at 11:26
  • If the error was that the closure was read-only, wouldn't the error occur on the assignment line rather than the print statement? –  Dec 30 '11 at 11:38
  • I know it doesn't make sense, but this behavior depends of the implementation. I'd be curious to see what happens in Jython or IronPython. @ElenaT: there is absolutely nothing in the documentation about it, you can find blog post from frustrated people here and there. I put a link in my answer. This sucks because you do use closure a lotwhen you create decorator. – Bite code Dec 30 '11 at 11:43
  • 1
    the problem here looks more like variable scope problem than read-only closure problem. local `a` scope in cpython starts at the beginning of the function (and probably other blocks that can have their own locals) instead of at first assignment, which is very counter-intuitive IMO. – soulcheck Dec 30 '11 at 11:51
  • It's not a bad error message. `a` is considered local if a is assigned in the current block and no `global a` is declared. See in [this Python doc](http://docs.python.org/3/reference/executionmodel.html#naming-and-binding). – Fish Monitor Mar 24 '13 at 13:53
0

The comment space is too small to fit the quotes below, so I post a new answer here.

I think this is variable scope problem. In the Execution Model of Python doc it says:

If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.

Fish Monitor
  • 4,155
  • 3
  • 32
  • 53