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%%\033[A' % int(percent)

ftp.upload(filename, temp_path, callback=progress_print)
Was it helpful?

Solution

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.

OTHER TIPS

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top