Reason for unintuitive behavior of UnboundLocalError

Note: there is a very similar question here. However, the bear is with me; my question is not, "Why does the error occur," but "Why was Python implemented to throw an error in this case."

I just stumbled upon this:

a = 5 def x() print a a = 6 x() 

throws an UnboundLocalException . Now I know why this happens (later in this area, a bound, so a is considered local throughout the area).

In this case:

 a = 5 def x() print b b = 6 x() 

it is very important. But the first case has intuitive logic, which should mean this:

 a = 5 def x() print globals()["a"] a = 6 # local assignment x() 

I suppose there is a reason the "intuitive" version is not allowed, but what is it? Although this may be the case of “Explicit is better than implicit”, messing around with globals() always feels a little unclean to me.

To put this in perspective, the actual case when this happened to me was someone else's script, I had to change for a moment. In my (short-lived) change, I did some file renaming while the script was running, so I inserted

 import os os.rename("foo", "bar") 

in the script. This insertion takes place inside the function. The module already imported os at the top level (I did not check this) and some os.somefunction calls that were made inside the function, but before my insertion. These calls explicitly UnboundLocalException .

So, can someone explain to me the reasoning for this implementation? Does the user stop making mistakes? Will there be an “intuitive” way to just complicate the work of the bytecode compiler? Or is there a possible ambiguity that I did not think about?

+4
source share
3 answers

Having the same thing, an identical name refers to completely different variables within the same stream of linear code, so it is a staggering complexity that it waves the mind. Consider:

 def aaaargh(alist): for x in alist: print a a = 23 

What should this code do in your preferred Python version? If a in the same expression print refers to completely different and unrelated variables at the first stage of the cycle versus the second (if it is the second)? Does this work differently even for an attribute with a single element than code without a loop? Seriously, in this way, the insanity lies - not even thinking about the terrible implementation problems, just trying to document and teach, this is what will probably make me switch languages.

And what will be the fundamental motivation for the language, its performers, its teachers, its students and their practitioners to take on all this conceptual burden - to support and encourage the half-hidden, implicit use of GLOBAL VARIABLES ?! It hardly seems a worthwhile goal, is it doing it now ?!

+5
source

I believe there is a possible ambiguity.

 a = 5 def x(): print a a = 6 # could be local or trying to update the global variable x() 

It could be as you expected:

 a = 5 def x(): print globals()["a"] a = 6 # local assignment x() 

Or maybe they want to update the global variable to 6:

 a = 5 def x(): global a print a a = 6 x() 
+1
source

This is the main side effect of the review. The python developers decided that global variables should not be available in the area in which you are trying to use it. Take this for example:

 a = 5 def x(): a = 6 print a x() print a 

This outputs 6 5 .

It is generally considered bad practice to have global variables anyway, so python developers have limited this. You must explicitly make the global variable available to access it. This actually prevents ambiguity. Consider this:

 a = 5 def x(): a = 6 print a y() def y(): global a a = a + 1 print a x() print a 

If x() is considered a local and does an assignment, this would print 6 6 7 . Whoever wrote x() might not have thought that y() would use a global variable called a . Thus, causing y() act abnormally. Fortunately, python scopping does this in such a way that the x() developer does not need to worry about how the y() developer y() implemented, only that he does what he needs to. As a result, it outputs 6 6 6 (digits), as expected.

As a result, a UnboundLocalException completely intuitive.

0
source

All Articles