0

While attempting to create a simple message encrypting code in Python (3.6.3), I encountered a problem, which can be observed in the following code (separate test file):

import sys


def test(integ):
    integ += 1
    return


def main():
    x = 0
    y = 2
    test(x)
    test(y)
    print("{}\n{}".format(x, y))
    test(x)
    print(x)


if __name__ == "__main__":
    main()

Now, my goal is for it to give me 1, 3 and 2 in that order as an output, but it gives me 0, 2 and 0, meaning that the variables x and y aren't modified at all. So, after looking up possible solutions to my issue, I found the statement nonlocal and attempted to alter my code in the following way:

def test(integ):
    nonlocal integ
    integ += 1
    return

However, this time I obtain the following error: SyntaxError: name 'integ' is parameter and nonlocal, which leads me to the conclusion that I can not alter the variables x and y using a parameter within the function test().

Would there be some sort of workaround for this issue while avoiding the use of global variables?

4
  • 1
    That's not how variables work in Python. See nedbatchelder.com/text/names.html Commented Nov 3, 2017 at 22:23
  • If you are already calling test(smth), why not return the new value and simply reassign smth = test(smth)? Commented Nov 3, 2017 at 22:24
  • 1
    nonlocal isn't what you want here. Python integers are immutable, you can't change them. Your test function needs to create a new integer object with the value you want and then return that new object to the calling code, by using the return statement. Commented Nov 3, 2017 at 22:25
  • @grovina The reason why I don't do it is because I wish to reuse the same function multiple times without having to reassign it manually every single time. This is especially bothersome if I wish to do it for multiple variables (say, not just 2 like in this example, but maybe 30 different ones). Having a simple solution would be more beneficial. The second solution Brett suggested solved my issue thankfully. Commented Nov 3, 2017 at 23:07

2 Answers 2

2

test just receives the value you're passing in, not a reference to the variable. An easy solution would be to reassign a return value:

>>> def test(integ):
...     return integ + 1
...
>>> x = 0
>>> x = test(x)
>>> x
1

If you want to return more than one value this way, the Pythonic way is through a tuple (which Python will pack/unpack for you, as shown):

>>> def test(integ):
...     return integ + 1, integ - 1 # same as `return (integ + 1, integ - 1)`
...
>>> test(0)
(1, -1)
>>> x = 0
>>> x, z = test(x) # same as `(x, z) = test(x)`
>>> x
1
>>> z
-1

Another option would be to wrap the value in something mutable (like a dictionary):

>>> def test(integ):
...     integ['value'] += 1
...     return
...
>>> x = {'value': 0}
>>> test(x)
>>> x['value']
1
Sign up to request clarification or add additional context in comments.

2 Comments

First off, thank you for the quick reply. However, I have another question regarding the first method you proposed. Would there be a way for test(integ) to return two separate values? Or would it be more favorable to rely on the second method you proposed in that case?
Python makes it really easy to return more than one value. I added an example below the first method.
1

same workaround technique (see Brett answer) with a list instead:

>>> def f1(a_mutable_var):
...     a_mutable_var[0] += 1
... 
>>> L1 = [1]
>>> f1(L1)
>>> L1
[2]
>>>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.