Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 SyntaxWarning variable used prior to global declaration

I get the following error:

Warning (from warnings module):
File "C:\Python34\projectEuler\projectEuler.py", line 316
global primeSet, primeList, primeCap, primeRan
SyntaxWarning: name 'primeRan' is used prior to global declaration

For the code:

primeSet = {2, 3}
primeList = [2, 3]
primeCap = 3
primeRan = False
def primeGen():
  if primeRan:
    primeList, primeCap = primeList, PrimeCap
    global primeSet
  else:
    global primeSet, primeList, primeCap, primeRan
    primeRan = True
  for i in primeList:
    yield i
  while(True):
    primeCap += 2
    m = int(primeCap**.5)
    yesPrime = True
    for p in primeList:
        if p > m: break
        if primeCap%p == 0:
            yesPrime = False
            break
    if yesPrime:
        primeSet.add(primeCap)
        primeList.append(primeCap)
        yield primeCap

The variable is not written until it is assigned. And the code seems to work. Is the syntax message a false alarm, or should a global be declared before being read? (instead of only declaring before being written)

The code:

def primeGen():
    global primeRan  
    if primeRan:
        primeList, primeMax = primeList, PrimeCap
        global primeSet
    else:
        global primeSet, primeList, primeCap
        primeRan = True

Gets rid of the SyntaxWarning. But it seems wrong to make the global deceleration for a value that is only being read and not written.

Should I ignore the syntax alarm?

like image 654
kjl Avatar asked Mar 10 '23 06:03

kjl


1 Answers

No, you can't ignore it and, as of Python 3.6 this will cease to be a SyntaxWarning and instead be updated to an error (SyntaxError). So you better fix it now or face it the prospect of it not executing in future versions (>= 3.6) .

See the docs on the global statement:

Names listed in a global statement must not be used in the same code block textually preceding that global statement.

As you noticed, this isn't a warning that is generated at run-time, it is generated when Python compiles your function object and notices a global statement containing a name (primeRan) that has already been found as local.

You should add the global statement before referencing primeRan here and also do the same for primeList which falls victim to the same issue.

For primeList, though, you can be sneaky and take advantage of the fact that global must be parsed first. In short, switch the condition over so Python parses the global statement for it before the assignment statement:

 def primeGen():
     global primeRan
     if not primeRan:
         global primeSet, primeList, primeCap
         primeRan = True
     else:
         primeList, primeMax = primeList, PrimeCap
     # rest as is

Since global is a directive for the parser, this yields the same behavior w/o the warning.

Of course, using globals is not a good practice. I can't see any reason why you'd require using them to be honest, you're always better off (and from a conceptual point of view and execution speed wise) to drop the usage of globals and instead communicate with your function using arguments and return values.

like image 171
Dimitris Fasarakis Hilliard Avatar answered Apr 25 '23 03:04

Dimitris Fasarakis Hilliard