Reputation: 1085
Usually in a local function I should be able to access any variable declared in enclosing scope. But I'm getting Unresolved reference error. Here is the code snippet.
import time
def make_timer():
last_called = None
def elapsed():
now = time.time()
print(last_called)
# nonlocal last_called
if last_called is None:
last_called = now
return None
elapsed_time = now - last_called
last_called = now
return elapsed_time
return elapsed
Accessing last_called gives unresolved reference error.
Upvotes: 2
Views: 2902
Reputation: 36
The error arises because of the assignments to last_called
inside the elapsed
function. A variable that isn't declared as global
or nonlocal
and gets assigned a value inside the function is a local variable. At the point you're accessing the variable it hasn't been assigned a value yet which causes the error.
import time
def make_timer():
last_called = None
def elapsed():
now = time.time()
print(last_called)
if last_called is None:
last_called = now # <-
return None
elapsed_time = now - last_called
last_called = now # <-
return elapsed_time
return elapsed
More info can be found here: Why can functions in Python print variables in enclosing scope but cannot use them in assignment?
Upvotes: 1
Reputation: 5372
last_called = None
The object named last_called
is immutable. To change the content of the
object will release the object and assign a new object.
print(last_called)
Looks like debugging code. last_called
is seen as the immutable object which
has not been declared as a nonlocal name yet.
# nonlocal last_called
Even if you uncommented this line, it is after the access of lasted_call
by the use of the previous print
. This is too late to change the scope.
last_called = now
This is assignment. The print(last_called)
references None
in a
different scope and the object is immutable and now attempt to assign a value to it.
The elapsed
function wants to access the immutable object named last_called
.
The interpreter progresses to the assignment and cannot continue.
Exception is raised.
Possible options for the behavior of last_called
within elapsed
:
If nonlocal last_called
is used, then declare before access and assignment.
if nonlocal last_called
is not declared, then access before assignment causes
an exception.
if nonlocal last_called
is not declared, access after assignment uses
a local name last_called
.
Your code order may work better as:
import time
def make_timer():
last_called = None
def elapsed():
now = time.time()
nonlocal last_called # declare scope
print(last_called) # access
if last_called is None: # access
last_called = now # assign
return None
elapsed_time = now - last_called # access
last_called = now # assign
return elapsed_time
return elapsed
nonlocal last_called
is uncommented as it is required for option 1.
Upvotes: 3