0

Why doesn't the variable url change?

def test():
    url = "Start"

    def change():
        global url
        url = "End"

    change()
    print(url)

    return url

test()

And yes, it needs to be a function within a function. That way the rest of my code is more simple. Thanks for your help!

2
  • Another approach to this is to put url in a mutable container, e.g. a list -- url = ["Start"]; url[0] = "End"; return url[0]. No global/nonlocal needed that way. Commented Dec 31, 2021 at 15:18
  • @Samwise I'd prefer a dataclass with unfrozen values. Commented Dec 31, 2021 at 15:21

2 Answers 2

2

Global variables are those defined at the top-level scope of a module, not just any variable defined outside the scope of a function. The variable defined in test is a nonlocal variable from change's perspective, not a global variable.

Use the nonlocal keyword instead:

def test():
    url = "Start"

    def change():
        nonlocal url
        url = "End"

    change()
    print(url)

    return url

nonlocal causes the assignment to take place in the closest enclosing scope where url is defined. (If no such local scope exists, the nonlocal declaration is a syntax error. A definition in the global scope does not count, in contrast with free variables who are looked up in the closest enclosing scope, whether local or global.)


In your original function, change really does set (or even create) a global variable named url. For example:

def test():
    url = "Start"

    def change():
        global url
        url = "End"

    change()
    print(url)

    return url

try:
    print(url)
except NameError:
    print("'url' not yet defined")

test()  # Outputs "Start"
print(url)  # Outputs "End"
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you! I have coded in python for a year now and I had never heard of that keyword before xd
It's relatively new, having been introduced in Python 3. If you are coming from a Python 2 background, you may not realize it exists, and even if you started in Python 3, you may not necessarily recognize when a use-case for it exists.
The assignment creates the variable, not the nonlocal declaration itself.
Hm. That does seem to be the case if no non-local variable exists (even if a true global does as well). I had a more complicated example with more levels of nesting, where it seemed to create a new local variable in the immediate local scope without affecting a pre-existing url higher in the stack. And of course I've already deleted the file. Let me see if I can recreate it to figure what I actually did.
OK, I misinterpreted a regular free-variable lookup in the closest enclosing scope with the creation of a new local variable.
1

The solution is to use the nonlocal keyword

def test():
    url = "Start"
    def change():
        nonlocal url
        url = "End"

    change()
    print(url)

    return url

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.