-1

I understand the logic behind requiring global if a global variable is assigned to within a function, but I don't understand why this can't be done:

y = 0
def x():
    y = y
    # Now modify the local version, but not the global one

Calling x results in an UnboundLocalError, even though there's no ambiguity here: The right-hand side of the assignment should be evaluated to the global variable since y is undefined in a local scope when it is executed.

This question is similar to this one (which doesn't have any detailed answers), but is more about the reasoning behind the language design.

I wouldn't write code like that because it is confusing, but I don't see why the language would forbid it. It seems inconsistent with how globals (or for that matter nonlocals) usually behave in python.

chuck
  • 1,420
  • 4
  • 19
  • Because the syntax for using a local variable `y` or for a global variable `y` is the same. You can circumvent this by updating `globals()`. If Python guessed the meaning you describe (without any error), if would be a source of bugs and confusion to beginner (and non-beginner) programmers. – khelwood Sep 26 '20 at 20:03
  • @khelwood But not in this scenario - The right side must be global (becuase there isn't a local yet), and the left side must be local becuase there is no `global y` in the function, which is required for global assignment. Then in the rest of the function everything refers to the local one becuase that's how scopes work. There's only one way to interpret the code. – chuck Sep 26 '20 at 20:06
  • 1
    There is another way to interpret the code, which is that it is a programmer error. Either they forgot to initialise a variable or they forgot the `global` statement. Better that the code should error than do something no one expects. – khelwood Sep 26 '20 at 20:08
  • Right, but it might not be a programmer error, and it is consistent with how the rest of the language works. "It is probably a programmer error" is just an excuse for edge-cases, I'm looking for an actual explanation / official reasoning behind this behaviour, or an example of why this actually *is* inconsistent with the language. – chuck Sep 26 '20 at 20:15
  • 1
    @chuck The mere *presense* of an assignment to a name (not marked as global or non-local) is what makes `y` a local variable at *compile* time. There is no way to specify that the RHS should be the global name. – chepner Sep 26 '20 at 20:45
  • The fact that a plausible interpretation *exists* doesn't mean that it's better language design to use that interpretation than to make it an error. Your proposed use case is already served by `some_other_variable = y` - there's no actual benefit to reusing the `y` name. Allowing the use of `y = y` would just be confusing and error-prone. – user2357112 Sep 26 '20 at 21:02

1 Answers1

1

When a variable name is used on the left-hand side of an assignment statement Python creates a local variable. When a local variable has the same name as a global variable we say that the local shadows the global. A shadow means that the global variable cannot be accessed by Python because the local variable will be found first.

you're using an assignment statement on y inside the function.

The Python interpreter sees this at module load time and decides that the global scope's y should not be used inside the local scope, which leads to a problem when you try to reference the variable before it is locally assigned.

that is the reason you would need to add

y=0
def x():
    global y
    y=y
x()

This will tell Python that you don't intend to define a y variable inside the function's local scope. The Python interpreter sees this at module load time and decides to look up any references to the aforementioned variables in the global scope.

Though it is one of several good reasons for not using global variables. As you can see, it makes your code confusing and difficult to understand, one should refrain from doing this in code. I suggested adding a global keyword just to cement the understanding of how python is working here.

Arshad
  • 66
  • 5
  • Ok, thanks. I guess what I didn't get was that the compiler actually marks the scope of a variable as soon as it appears in the source, rather than when the actual assignment happens. – chuck Sep 26 '20 at 21:00
  • Python fairly easily could have been designed so that failed local lookups fall back to globals, though. It'd just be a few extra lines of code in `Python/ceval.c`. Global lookups already have a similar fallback to builtins - you trigger this fallback every time you access a builtin. There's no local->global fallback because such a fallback would cause more problems than it solves. – user2357112 Sep 26 '20 at 21:10