Local variable referenced before assignement

Question:

I am going crazy. This simple callback function doesn’t recognize a variable assigned right before it in it’s parent scope. I get a local variable 'elapsed' referenced before assignment error`. Why?

total = os.path.getsize(filename)
elapsed = 0

def progress_print(chunk):
    elapsed += len(chunk)  # elapsed is apparently unassigned??
    percent = float(elapsed) / float(total) * 100
    print '  Copied %s%%33[A' % int(percent)

ftp.upload(filename, temp_path, callback=progress_print)
Asked By: MFB

||

Answers:

You’re trying to assign to a global. Python makes you explicitly do that.

def progress_print(chunk):
    global elapsed
    elapsed += len(chunk)

In general this is a pretty good sign that you need to refactor your code until you don’t need globals any more.

Note that assignment and access are different beasts – the former requires you to explicitly declare globals, the latter does not. Case in point, your total variable is another global but you do not attempt to assign to it, hence python does not complain.

The Programming FAQ goes into more detail:

What are the rules for local and global variables in Python?

In Python, variables that are only referenced inside a function are
implicitly global. If a variable is assigned a new value anywhere
within the function’s body, it’s assumed to be a local. If a variable
is ever assigned a new value inside the function, the variable is
implicitly local, and you need to explicitly declare it as ‘global’.

Though a bit surprising at first, a moment’s consideration explains
this. On one hand, requiring global for assigned variables provides a
bar against unintended side-effects. On the other hand, if global was
required for all global references, you’d be using global all the
time. You’d have to declare as global every reference to a built-in
function or to a component of an imported module. This clutter would
defeat the usefulness of the global declaration for identifying
side-effects.

Answered By: roippi

When you do a

def progress_print(chunk):
    elapsed += len(chunk)

Here elapsed is the new local variable. Since you are doing a +=, which is nothing but:

elapsed = elapsed + len(chunk)  

Here, elapsed is not initialized with any value, that is why you get the error – referenced before assignment.

Hence you need to do:

def progress_print(chunk):
    global elapsed
    elapsed += len(chunk)
Answered By: doubleo
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.