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"
urlin a mutable container, e.g. a list --url = ["Start"];url[0] = "End";return url[0]. Noglobal/nonlocalneeded that way.