Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"local variable referenced before assignment" — only functions?

Tags:

python

scope

Take the following code:

import something

def Foo():
    something = something.SomeClass()
    return something

…this is apparently not valid code:

UnboundLocalError: local variable 'something' referenced before assignment

…as the local variable something is created, but not assigned, before the RHS of the = is evaluated. (See, for example, this related answer's comment.) This seems a bit odd to me, but sure, I'll go with it. Now, why is the following valid code?

class Foo(object):
    something = something.SomeClass()

My understanding was that the inside of a class definition was essentially a scope:

The class’s suite is then executed in a new execution frame (see section Naming and binding), using a newly created local namespace and the original global namespace.

So, then, why does that code act differently than that of a function?

like image 714
Thanatos Avatar asked Jan 31 '12 23:01

Thanatos


People also ask

How do I fix local variable referenced before assignment?

The Python "UnboundLocalError: Local variable referenced before assignment" occurs when we reference a local variable before assigning a value to it in a function. To solve the error, mark the variable as global in the function definition, e.g. global my_var .

How do you deal with UnboundLocalError?

UnboundLocalError can be solved by changing the scope of the variable which is complaining. You need to explicitly declare the variable global. Variable x's scope in function printx is global. You can verify the same by printing the value of x in terminal and it will be 6.

What is an UnboundLocalError?

The UnboundLocalError: local variable referenced before assignment error is raised when you try to assign a value to a local variable before it has been declared. You can solve this error by ensuring that a local variable is declared before you assign it a value.

What is the difference between nonlocal and global in Python?

An important difference between nonlocal and global is that the a nonlocal variable must have been already bound in the enclosing namespace (otherwise an syntaxError will be raised) while a global declaration in a local scope does not require the variable is pre-bound (it will create a new binding in the global ...


2 Answers

From the python class documentation:

Class definitions place yet another namespace in the local scope.

A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects. The same is true for deletions: the statement del x removes the binding of x from the namespace referenced by the local scope. In fact, all operations that introduce new names use the local scope: in particular, import statements and function definitions bind the module or function name in the local scope. (The global statement can be used to indicate that particular variables live in the global scope.)

So within a function (or a scope) the assignment creates a local unbound variable that is accessed before it is bound, whereas in a class definition it creates an entry in the "namespace" dictionary of that class on assignment, allowing the resolution of something to the outer namespace (the module namespace).

like image 71
Novikov Avatar answered Oct 17 '22 14:10

Novikov


Consider the following example which may help to clarify this:

import datetime

class Foo(object):
    datetime = datetime.datetime

>>> datetime
<module 'datetime' from '/usr/lib/python2.6/lib-dynload/datetime.so'>
>>> Foo.datetime
<type 'datetime.datetime'>

Note that the line datetime = datetime.datetime is actually assigning to the name Foo.datetime, which is not ambiguous with the global datetime (like it would be if the same code were in the function).

In summary, because class definitions create a new namespace as well as a new scope, you are allowed to directly access a name in an enclosing scope and assign to the same name in the local scope.

like image 38
Andrew Clark Avatar answered Oct 17 '22 15:10

Andrew Clark