user1748155
user1748155

Reputation: 1375

objects not being passed to function in flask route

I have a function and a flask route setup. However, when I go to "simplepage", I get an error "NameError: global name 'aaa' is not defined". Why aren't any of the objects being passed to testfun? Is this something due to the app.route decorator, or due to flask? Can I make all the objects passed to testfun? My actual code is way more complicated with many more objects that would need to be passed, but this simplified scenario was created to illustrate my issue.

def testfun():
    b=aaa

@app.route("/simplepage/", methods=['GET'])
def simplepage():
    aaa=1
    testfun()
    return flask.render_template('page.html')

Upvotes: 1

Views: 1436

Answers (2)

Sean Vieira
Sean Vieira

Reputation: 159895

This is due to Python's scoping rules (as @johnthexiii pointed out) - testfun->aaa is bound to the global scope because there is no variable named aaa declared anywhere inside of testfun and there is no enclosing scope (i. e. testfun is not declared inside another function or class).

You'll want to pass aaa as an argument to testfun:

testfun(aaa)

If testfun requires too many params there are several ways you can DRY up the code:

  • Use multiple functions: If testfun is doing a lot of work then break it up into multiple functions that return intermediate transformations of the data:

    def start_test(arg1, arg2, arg3):
        # do stuff with args
        return result_stage_1
    
    def continue_test(arg3, arg4, arg5):
        # do stuff with args
        return result_stage_2
    
    def finalize_test(arg7, arg8):
        # do stuff with args
        return real_result
    
  • Use keyword arguments: If a variable number of arguments are needed and testfun cannot be broken up you can use keyword arguments to simplify the calling of the function:

    def testfun(arg1=None, arg2=None, arg3=None, arg4=None,
                  arg5=None, arg6=None, arg7=None, arg8=None):
        # do stuff with args
    
    # call it as so
    args = {"arg1": "some args", "arg5": "have defaults"}
    if complex_condition:
        args["arg3"] = 17
    elif another_condition:
        args["arg7"] = 10
    
    testfun(**args)
    
  • Encapsulate state and behavior with classes (or closures): If neither of the above will work for you then you probably need to leave the realm of stateless functions and create classes or closure-creating functions to preserve your state and enable you to modify behavior as needed.

Upvotes: 3

John
John

Reputation: 13699

Basically what is happening is this

def t():
    print aaa 

def s():
    aaa = "hi"
    t()

s()

Python looks for aaa first in the local scope, then in any wrapping function scopes, then globally, and lastly in the builtins. Since the s functions scope isn't any of those things python throws an undefined error because it can't find aaa.

One solution would be to declare aaa as global.

def t():
    print aaa

def s():
    global aaa
    aaa = "hi"
    t()

s()

Upvotes: 1

Related Questions