views:

50

answers:

2

I get an UnboundLocalError because I use a template value inside an if statement which is not executed. What is the standard way to handle this situation?

class Test(webapp.RequestHandler):
    def get(self):      
        user = users.get_current_user()
        if user:
            greeting = ('Hello, ' + user.nickname())
        else:
            self.redirect(users.create_login_url(self.request.uri))
...

        template_values = {"greeting": greeting,
                       }

Error:

UnboundLocalError: local variable 'greeting' referenced before assignment
+2  A: 

Just Switch:

class Test(webapp.RequestHandler):
    def err_user_not_found(self):
        self.redirect(users.create_login_url(self.request.uri))
    def get(self):      
        user = users.get_current_user()
        # error path
        if not user:
            self.err_user_not_found()
            return

        # happy path
        greeting = ('Hello, ' + user.nickname())
        ...
        template_values = {"greeting": greeting,}
fabrizioM
@fabrizioM: Thanks for the answer. I used `greeting=None` for now; but when I am ready to deploy the app I may use this version. What does `return` do? Why is it necessary?
Zeynel
@Zeynel It exits from the routine, otherwise the interpreter will continue executing all the following statements.
fabrizioM
+1  A: 

I guess I need to explain the problem first: in creating template_values, you use a greeting variable. This variable will not be set if there is no user.

There isn't a standard way to handle this situation. Common approaches are:

1. make sure that the variable is initialized in every code path (in your case: including the else case)
2. initialize the variable to some reasonable default value at the beginning
3. return from the function in the code paths which cannot provide a value for the variable.

Like Daniel, I suspect that after the redirect call, you are not supposed to produce any output, anyway, so the corrected code might read

class Test(webapp.RequestHandler):
  def get(self):      
    user = users.get_current_user()
    if user:
        greeting = ('Hello, ' + user.nickname())
    else:
        self.redirect(users.create_login_url(self.request.uri))
        return
...

    template_values = {"greeting": greeting,
                   }
Martin v. Löwis
@Martin v. Löwis: Thanks. It seemed the second option is the easiest so I chose `greeting=None`. Why is `return` necessary?
Zeynel
self.redirect will only instruct webapp to send a redirect - it is a regular function and cannot really abort the execution of get() (except when it would raise an exception). So if you don't want to / must no perform any further action after the redirect, you really should return from the get right away, and avoid performing more activity (which then is either incorrect or unneeded).
Martin v. Löwis