-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ruff picks wrong scope for variable #4486
Comments
Interesting, thank you for filing. |
Do you understand why this runs without error? class A:
T = range(10)
Z = (x for x in T)
L = [x for x in T]
B = dict((i, str(i)) for i in T) |
Ah, so this scoping only applies to the generator body, and not the iterable. |
Yes, your example initially threw me off, but I think in this case the iterable can be thought of like the function signature (e.g. the defaults of the arguments), it's scope is in the outer area and the body is like a function body. |
Here's another interesting wrinkle -- this does not work: class A:
T = range(10)
L = [x for x in T for y in T] I noticed this via the comment in Carl Meyer's finder tool. |
So it's only the first generator (?) that's evaluated in the parent scope. |
Right, expanding my analogy same how the signature of bar fails here: class A:
T = range(10)
def foo(x=T):
def bar(y=T):
pass
return bar()
foo() |
Thank you, that's a really helpful model. |
Specifically, Ruff incorrectly identifies the scope a variable is chosen from when it's inside a comprehension inside a class inside a function and a variable with the same name exists inside the class scope.
Here is shortest code to reproduce this example, I named it
scopetest.py
:Running Ruff:
If I run
ruff
with--fix
it deletes the line that b is sourced from causing the code to now throw an exception.The reason b is scoping from the function scope and not the class scope is that generators / comprehensions implicitly create an anonymous function and source their scope from locals, non-locals, globals, and builtins and skip the class scope as all other functions do.
I came across this testing different versions of code posted here where the Steering Council has decided to keep the behavior as-is for at least Python 3.12.
The text was updated successfully, but these errors were encountered: