GeezerVison is showing github.com — global declaration in except has incorrect prior use · Issue #111123 · python/cpython
global declaration in except has incorrect prior use #111123Labels interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error DescriptionBug report
Bug description:
I think the global a has no prior use in this code (and pyright tells me the same). But I don't understand why cpython thinks it has a prior use.
a=5
def f():
try:
pass
except:
global a
else:
print(a)
output (Python 3.12.0):
File "/home/frank/projects/pysource-playground/pysource-codegen/bug.py", line 8
global a
^^^^^^^^
SyntaxError: name 'a' is used prior to global declaration
the following code has no syntax error:
a=5
def f():
try:
pass
except:
global a
print(a)
I can also reproduce this issue in 3.7.
I also don't know what the exact semantic of global/nonlocal inside statements like if/while/try/... is. I would like to know more about it because I'm currently writing pysource-codegen where I generate such cases.
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Linked PRs
Activitysobolevn commented on Oct 20, 2023 iritkatriel commented on Oct 20, 2023 I think this is because symtable_visit_stmt visits the else clause before the handlers:
case Try_kind:
VISIT_SEQ(st, stmt, s->v.Try.body);
VISIT_SEQ(st, stmt, s->v.Try.orelse);
VISIT_SEQ(st, excepthandler, s->v.Try.handlers);
VISIT_SEQ(st, stmt, s->v.Try.finalbody);
break;
Reacted by Jelle Zijlstra JelleZijlstra commented on Oct 20, 2023 The converse of this bug is that this code currently works (and prints 1):
a = 0
def f():
try:
1 / 0
except:
a = 1
else:
global a
f()
print(a)
With Irit's fix, this would instead be a SyntaxError.
I don't know if any code in existence would rely on this weird behavior, but we should probably fix this only on main (not the bugfix branches) and call out the change in behavior in What's New. 15r10nk commented on Oct 21, 2023 ContributorAuthor More actions I agree @JelleZijlstra
I think I understood how the logic behind global works.
a=0
def f(cnd,value):
if cnd:
global a
a=value
f(True,1)
print(a)
f(False,2)
print(a)
output (Python 3.12.0):
global is not affected by the actual order of execution. It is more "the line" in which it was declared.
The syntax error for prior use exists mainly to safe the user from thinking that he could put the global behind the use of some variable and to expect a different behavior.
Leaving out a lot of other wired uses like the if above.
A SyntaxWarning might be useful here, but I also don't know if this generated code is representative for real world problem. Hard to tell if such a SyntaxWarning could help someone.
@iritkatriel I saw your fix and I think TryStar is also affected by this bug. iritkatriel commented on Oct 21, 2023
@iritkatriel I saw your fix and I think TryStar is also affected by this bug.
Right, thanks. added a commit that references this issue on Oct 21, 2023gh-111123: symtable should visit exception handlers before the else b…
MetadataMetadatainterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error DevelopmentNo branches or pull requestsIssue actions
|