Skip to content

global declaration in except has incorrect prior use #111123

Closed

Description

@15r10nk

Bug 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

Activity

  1. sobolevn commented on Oct 20, 2023

    @sobolevn
    Member

    I feel like this issue might be interesting to @iritkatriel and @pablogsal.

  2. iritkatriel commented on Oct 20, 2023

    @iritkatriel
    Member

    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;
    
  3. added a commit that references this issue on Oct 20, 2023
  4. JelleZijlstra commented on Oct 20, 2023

    @JelleZijlstra
    Member

    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.

  5. 15r10nk commented on Oct 21, 2023

    @15r10nk
    ContributorAuthor

    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):

    1
    2

    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.

  6. iritkatriel commented on Oct 21, 2023

    @iritkatriel
    Member

    @iritkatriel I saw your fix and I think TryStar is also affected by this bug.

    Right, thanks.

  7. added a commit that references this issue on Oct 21, 2023
  8. added a commit that references this issue on Feb 11, 2024
  9. added a commit that references this issue on Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions