Returning Variables in Functions Python Not Working Right

Question:

I have been trying to return a variable in a function in a variable and use it outside of it:

test = 0

def testing():
    test = 1
    return test

testing()
print(test)

But when I run it, the result is 0. How could I fix this problem?

Asked By: alexswear

||

Answers:

You are messing up a bit the scopes and/or assignment. Try this:

def testing():
    test = 1
    return test

test = testing()
print(test)

Explanation: The test inside testing is different to the test inside the module. You have to assign it on module-level to get the expected result.

Answered By: Hyperboreus

Because you declare test in the function, it is not a global variable, thus, you can not access the variable test you created in the function outside of it as they are different scopes

If you want to return test to a variable, you have to do

result = testing()
print(result)

Or, you can also add a global statement:

test = 0

def testing():
    global test
    test = 1
    return test

testing()
print(test)

By the way, when doing a conditional statement, you don’t need the brackets around the 1==1 :).

Answered By: TerryA

Inside the function testing(), you’re creating a new variable test, not referring to the one that already exists. If you want to do that, you should use a global statement in the top, as in:

def testing():
    global test
    ...etc...
Answered By: Eli Rose

Your test variable inside the function does not have a global scope. So, if you want to store the return value in a variable and output it after that, you can do something like this:

result = testing()
print(result)
Answered By: Amal Murali

TLDR: A return value must be assigned to something at the call site.

test = testing()

Functions in Python have their own scope. It is created on entering (calling) the function, and destroyed when leaving it. Assignment to a name inside a scope makes that name local to this scope – causing it to be destroyed along with the scope.

# start outer scope
test = 0  # create name outer:test

def testing():
    # start inner scope
    test = 1  # create name outer.testing:test
    return test
    # end inner scope
    # destroy name outer.testing:test

testing()  # new temporary inner scope outer.testing
print(test)  # use name outer:test
# end outer scope

Notably, names in an inner scope may “shadow” names from an outer scope. While the name test exists in both testing and the outer scope, it does not refer to the same thing. This has two important implications:

  1. The assignment to the inner test does not affect the outer test.
  2. At the end of testing, the inner test is destroyed and only the outer test remains.

This is why calling testing() does not have the desired effect: it never modifies the outer test passed to print.


The return statement defines the value returned by calling a function. It does not return the name, only the value pointed to.

def testing():
    test = 1  # test refers to the value 1
    return test  # return test => value 1

The value returned by a function is like any other value – be it from a literal, lookup, or other. Most importantly, the value does not persist unless you assign it to a name or use it directly.

testing()  # call test, discard its value
test = testing()  # call test, store its value as `test`
print(testing())  # call test, use its value in `print`

So in order to return something from a function for later use, you must store the result to a name. You can then use that name in a later statement. A minimal example for your case looks like this:

# we already can define testing here
# it is overwritten later on, then

def testing():
    # all names we use inside of testing are gone at the end
    # if we just want a value, we can skip temporary names
    return 1

# store the return value of testing() for later use
test = testing()
print(test)

Addendum: It is possible for a function to modify its containing scope. However, names must then be explicitly declared as being from a foreign scope.

The nonlocal and global keywords allow to modify names from outer scopes. A nonlocal is the name in the closest matching function scope. A global is the name at the module scope, regardless of any functions in-between.

test = 0

def increment():
    global test  # declare test as belonging to a specific scope
    test += 1
    # no need to return something
    # we already modified the outer `test`

print(test)  # 0
increment()
print(test)  # 1

Note that modifying outer names is often the sign of an anti-pattern, moreso for globals than nonlocals. Beyond small scripts, it gets difficult to trace what is accessing and modifying globals. Often, it is more appropriate to use classes or generators to hold state.

A function can always read names from its containing scope, provided it never writes to the same name. Such closures are very easy to create, and the lack of modification makes them easier to trace. Note that modifying a name anywhere in a function makes it local, unless declared global or nonlocal:

test = 0

def increment():
    global test
    test += 1

def show_test():
    # we never modify `test`, so it is fetched from the outside
    print(test)

def show_and_increment1():  # this function is broken!
    print(test)  # `test` is *not* the outer one, since we modify it in the function
    test += 1  # modifying `test` makes it local for the *entire* function

def show_and_increment2():  # this function works!
    global test  # force `test` to be global
    print(test)
    test += 1

show_test()  # 0
increment()
show_test()  # 1
show_and_increment2()  # 1
show_and_increment2()  # 2
show_and_increment2()  # 3
show_test()  # 4
show_and_increment1()  # UnboundLocalError: local variable 'test' referenced before assignment
Answered By: MisterMiyagi
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.