tags:

views:

378

answers:

6

Basically I have some variables that I don't want to preinitialize:

originalTime = None
recentTime = None
postTime = None

def DoSomething ( ) :
    if originalTime == None or (postTime - recentTime).seconds > 5 :
        ...

I get compile error on the if:

UnboundLocalError: local variable 'originalTime' referenced before assignment

As you can see, all the variables have different relationship that either has to be set right (time, time + 5, etc) or None at all, but I don't wanna set them to precalculated values when just declaring them to None is easier.

Any ideas?

A: 

You should use an try except block to catch this.

optixx
A: 

I just tried your code in the shell and I didn't get an error. It should work. Maybe post the entire code? You can also use try/catch.

Or maybe locals().has_key('originalTime') ?

Adrian Mester
+6  A: 

Your code should have worked, I'm guessing that it's inside a function but originalTime is defined somewhere else. Also it's a bit better to say originalTime is None if that's what you really want or even better, not originalTime.

Scott Kirkwood
Thanks for the is/not tip.
Joan Venge
Just to add to Scott's apposite advice on is None: keep in mind that "not originalTime" will match cases where originalTime is 0 or "" or False, whereas originalTime is None will match only those cases where originalTime is actually "None". Many developers use this difference to delineate variables that have not been specified from those that have no value in the execution context. (ie: def myfunc(somevar=None): if somevar is None: somevar = 5 # otherwise assume that somevar = 0 is deliberate)
Jarret Hardie
+1  A: 

If the if statement is inside a function, but the = None declarations are at the module-level, then the variables are out of scope inside the function. The simplest fix is to explicitly indicate that the variable identifiers are to be found in the global scope:

def doSomething():
    global originalTime
    if originalTime:
        print "originalTime exists and does not evaluate to False"

Many folks regard this as poor Python design, btw. If you agree with that assessment, and your architecture permits, you may wish to refactor your function so that it receives external dependencies as function arguments.

Jarret Hardie
Thanks, for the bad design I agree. If it was pure python, I wouldn't do this, but I am using the python integration of a 3d party app, which is done very badly and buggy, but that's what I have to use.
Joan Venge
A: 

There's not really any "pretty" way around this. Just based on the variable names that you've given, my first instinct is to create an object:

class SomeTimeClass(object):
    def __init__(self, recentTime=None, originalTime=None, postTime=None):
        self.recentTime = recentTime
        self.originalTime = originalTime
        self.postTime = postTime

time = SomeTimeClass()
if not time.recentTime::
    ...

This might work because it sounds like the variables are correlated. A couple of other options:

Wrap the procedure in a function:

def SomeFunc(recentTime=None, originalTime=None, postTime=None):
    if not recentTime:
        ...

Use a dict:

some_dict = {}

if not some_dict.get('originalTime', None): #return None if key doesn't exist
    ...
Jason Baker
Just out of curiosity, why was this voted down? Did I get something wrong?
Jason Baker
+2  A: 

I need to correct Jarret Hardie, and since I don't have enough rep to comment.

The global scope is not an issue. Python will automatically look up variable names in enclosing scopes. The only issue is when you want to change the value. If you simply redefine the variable, Python will create a new local variable, unless you use the global keyword. So

originalTime = None

def doSomething():
  if originalTime:
    print "originalTime is not None and does not evaluate to False"
  else:
    print "originalTime is None or evaluates to False"

def doSomethingElse():
  originalTime = True

def doSomethingCompletelyDifferent()
  global originalTime
  originalTime = True

doSomething()
doSomethingElse()
doSomething()
doSomethingCompletelyDifferent()
doSomething()

Should output:

originalTime is None or evaluates to False
originalTime is None or evaluates to False
originalTime is not None and does not evaluate to False

I second his warning that this is bad design.

AFoglia