2

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.

2 Answers 2

3
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:

  1. If nonlocal last_called is used, then declare before access and assignment.

  2. if nonlocal last_called is not declared, then access before assignment causes an exception.

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

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

Comments

1

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?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.