3

Most arguments about why the design decision was made to make for-loop variables not local to the loop suggest that there are popular use cases.

The obvious use case is this:

x = default_value
for x in iterator:
    # do stuff
# do something with x here

Unfortunately, often the first line is forgotten:

# should have set default value for x here
# but forgot
for x in iterator:
    # do stuff
# do something with x here

So when iterator is empty, they raise NameError if x was not defined earlier.

This mistake gets worse with nested loops:

for y in outer_iterator:
    # should have set default value for x here
    # but forgot
    for x in inner_iterator(y):
        # do stuff
    # do something with x

Here forgetting the x = default_value results in a silent error instead of an exception if inner_iterator(y) is empty on the second or later iteration through the outer loop.

Testing these situations is tough, because inner_iterator(y) is not an outside argument, so unless the test is lucky enough to somehow recreate the case when it's empty, the bug won't be detected.

Are all use cases fragile or is there a safe way to rely on the scoping rule of the for-loop variables?

Community
  • 1
  • 1
max
  • 49,282
  • 56
  • 208
  • 355

2 Answers2

0

There is no 100% safe way to rely on a variable being set inside a for-loop unless you can be 100% sure that the iterator is never empty. To achieve the 100% assurance, you could do something like for x in iterator or [None]:, but this poses a similar "remembering to do it" problem. It is probably more "pythonic" than setting defaults, but defaults may provide more clarity. The whole relying on for-loop scoping is similar to something like if (condition): x = something and then contemplating about what if I call x when condition is false? You probably would not write code like that anyway so why do it for for-loops? I like to make it a habit of declaring all variables that will be used outside upfront (e.g., setting all variables to None or some other default at the beginning of a function), but it just comes down to preference.

Paul Nordin
  • 121
  • 1
0

I agree that the most obvious reason for loops not to have their own scope, is the complications that would introduce when assigning values to variables in the outer scope.

But that does not necessarily mean the iterated value. Consider the following:

total = 0
for item in some_list:
    total += item

If the loop had its own variable scope, implementing this would be a nightmare.

One of the onsequences is that the item is also avaialable out of the loop, but that does not really mean there is a nice way (or as you say "safe" way) to use it.

You can use it, but then you have to be careful.

zvone
  • 18,045
  • 3
  • 49
  • 77