x = calculate_n_dogs()
# later
ok = all(x.status_code == 200 for x in my_other_responses)
# later
let_the_dogs_out(x)
# oh no, why isn't x n_dogs anymore x = calculate_n_dogs()
# later
ok = all(x.status_code == 200 for x in my_other_responses)
# later
let_the_dogs_out(x)
# oh no, why isn't x n_dogs anymorePython 2 did have the issue where list comprehensions (though still not generator expressions) didn't introduce a new scope, and so you could indeed get issues quite similar to your example above. This was corrected in Python 3.
All that said, I will agree that Python's scoping rules are pants-on-head crazy. In very nearly every other programming language under the sun, you declare variables at the point where they exist. In Python, you declare a variable when it exists somewhere else (and you then want to reassign it). This does mean that you don't need to put a "local" or "var" or what-have-you in front of each new variable you declare (which is basically the reason Python did it this way), but the semantics of the thing can take some getting used to.
I've run into similar issues where the variable was used in a for loop declaration rather than a list comprehension, but these are a bit easier to spot. Also, maybe people who don't use lua constantly won't be in the habit of thinking they can safely shadow locals with their looping variables.