Home > other >  Getting Python2 exec behaviour in python3: UnboundLocalError: local variable
Getting Python2 exec behaviour in python3: UnboundLocalError: local variable

Time:08-09

I am using some old code base that was initially written in python2. The devs say they have ported it to python3 however I found a all the code that uses exec is completely broken. Below you can find an example like the one I am trying to fix:

def function_with_exec(table):

    (sess, tgt) = 3, None
    try:
        exec("ec = some_object.{}_get_entry_count(sess_hdl=sess, dev_tgt=tgt)".
             format(table))
    except AttributeError:
        return []

    ec = some_function(ec)

When running this code, I get: `UnboundLocalError: local variable 'ec' referenced before assignment.

I have been reading that a way to modify the global ec variable from the exec function is to pass the globals() as second argument. However, when I do that, then the variables sess and tgt which are also used in the expression, become undefined too.

I really do not find a way to solve this.

CodePudding user response:

Python thinks ec is a local variable, which hasn't yet been assigned to, and you can't reference it before first assigning to it. Use the global statement at the start of your function, like so:

def function_with_exec(table):
    # ec now refers to the global variable, which presumedly already been as
    global ec
    (sess, tgt) = 3, None
    try:
        exec("ec = some_object.{}_get_entry_count(sess_hdl=sess, dev_tgt=tgt)".
             format(table))
    except AttributeError:
        return []
    
    ec = some_function(ec)

See 7.12. The global statement

The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals. It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.

You could also remove the call to exec by using getattr instead:

def function_with_exec():
    global ec
    
    (sess, tgt) = 3, None
    try:
        ec = getattr(some_object, f"{table}_get_entry_count")(sess_hdl=sess, 
                                                              dev_tgt=tgt)
    except AttributeError:
        return []
    
    ec = some_function(ec)
  • Related