Parentheses in global statement

Python supports parentheses in many statements:

from requests import (models, api,
                      auth)
# No error

with (open('README.md') as f,
      open('setup.py') as g):
    pass
# No error

a = b = c = d = e = f = 0
del (a, b, c,
     d, e, f)
# No error

However, the global and nonlocal statement currently does not support the use of parentheses, as demonstrated in this example:

def foo():
	global (a, b, c,
		    d, e, f)
# SyntaxError: invalid syntax

def foo():
    a = b = c = d = e = f = 0
    def bar():
        nonlocal (a, b, c,
                  d, e, f)
        a, b, c, d, e, f = range(6)

    return bar
# SyntaxError: invalid syntax

Adding parentheses support to the global and nonlocal statements would make Python more consistent. In the meantime, a practical solution for implementing multiline global statements is by utilizing a backslash, as shown below:

def foo():
    global \
        a, b, c, \
        d, e, f
# No error

def foo():
    a = b = c = d = e = f = 0
    def bar():
        nonlocal \
            a, b, c, \
            d, e, f
        a, b, c, d, e, f = range(6)

    return bar
# No error

It’s worth mentioning that backslashes can be employed in other statements as well, as evidenced in the following examples:

from requests import \
    models, api, \
    auth
# No error

with open('README.md') as f, \
        open('setup.py') as g:
    pass
# No error

a = b = c = d = e = f = 0
del \
    a, b, c,\
    d, e, f
# No error

Adding parentheses support for the global and nonlocal statement would provide more consistency. Though it is currently possible to use a backslash for multiline purposes, incorporating parentheses could lead to a smoother and more polished coding experience.

4 Likes

Well, one difference with the global/nonlocal statements are that they don’t do anything by themselves, they just modify how variables behave. So it’s exactly equivalent to just using multiple statements:

global a, b, c
global b, c, d

Which is as good as doing parentheses, one line less even. Would be nice for consistency, but I’m not sure it’s really worth the effort adding such a feature, updating tutorials, other implementations of Python, linters, etc would require.

1 Like

The global statement with so many names that they do not fit in a single line is a red herring. I do not think that we should encourage such style of coding.

7 Likes

I think this would be a good enhancement to make Python more consistent. It would esp. help newbies.

1 Like

Should import be more consistent?

import (sys, os)

Any time someone’s peppering code with huge numbers of global/nonlocal declarations, and ESPECIALLY if those are listing large numbers of variables, I want to ask if they’re aware that these are only necessary during assignment. Your examples here are only reading from the variables in question, but they’re toy examples so I can’t be sure.

To be clear: You do NOT NEED global/nonlocal statements if all you’re doing is referring to those variables! Save yourself the hassle!

(The other possible reason for huge numbers of globals is that something is masquerading as a class but implemented as a collection of loose functions - less common but also a good solution to “too many globals”.)

Yes, that as well. We already have:

from os import (chdir, system)

I know that some people prefer to write each import on its own line, but that gets clunky when you have more than just a few imports.

1 Like

Sure, but if you are working with packages such as pygame-zero, you do need to use the globalstatement quite a bit, in order to better structure your application, and pygame-zero is intended for newbies.

The reason for this is that such tools often simplify keeping state and use global variables for this instead of passing around a context variable or handle.

1 Like

I agree that this situation is rare and often discouraged. And it would be red herring. However, if we consider the criteria, it would also apply to the ‘del’ statement.
Also, other than treating it as a SyntaxError, it should be included in guidelines or style guides on avoiding too many global variables or global statement with so many names.

I can understand why you might have some reservations. However, I believe that the changes are relatively minor, as the interpreter and linters already has implemented the del statement and others.
Additionally, since this issue is not widely known, I don’t anticipate negative impacts on tutorials.

Hmm, I’m not familiar with it, but yeah, I’m sure there are some situations where you’ll be assigning to a lot of globals. But I’ve seen WAY too many cases where piles of global statements are used for things that are just being read from, enough that it’s worth asking the question.

1 Like

I think talking about abuse of global statements is out of focus.

del is very different from global. This is a valid syntax:

a = b = 1
del [a, b]

Do you consider idea of making global [a, b] a valid syntax?

del supports parentheses because the assignment statement supports parentheses. It supports also subscription (del a[b]) and attribute access (del a.b) which do not make sense in context of global. So please exclude del from a list of examples, it is of completely different kind.

1 Like

Aye. Until my function later assigns to one of them. Best case that
happens late enough to trigger an undefined variable exception, worst
case the assignment is early enough to just cause silent failure (by
changing the local variable and leaving the nonlocal one unaffected).

That said, I do do exactly what you suggest all the time (omit global,
nonlocal).

Enclosing multiple names in parentheses should be allowed. This applies to import names, global names, nonlocal names.

Interestingly, when you join multiple assert expressions, no syntax error is displayed, and neither is any exception raised (this is a bug):

a = 4
b = 4

assert\
    a == 4,\
    b == 1

On the other hand, both of these work:

print\
    ('foo')

(print
 ('foo'))

I can show you other examples of inconsistencies in parentheses and line joining, but my main point is that these inconsistencies should not exist.

That does not mean what you think it does. Try changing a to a different value and see what happens.

That’s why I’m calling it an inconsistency. A newbie might spend numerous hours or even days trying to figure out where the hidden bug lies.

It’s nothing to do with joining assert statements together, though. Python simply does not allow you to join assertions. So I’m not sure what’s “inconsistent” here - that you can’t join asserts, or that you can’t do it with parentheses?

Newbies should ideally get used to running a linter like Ruff. In my opinion, it would much more inconsistent for Pyhon to treat parenthesis specially in an assertion.

1 Like

They may also be confused by why if (a == 4, b == 1): doesn’t do what they expect, and for the same reason, but that doesn’t mean we need to change that either.

1 Like