4

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?

kjl
  • 311
  • 3
  • 13
  • Possible duplicate of [Why is the global keyword not required in this case?](http://stackoverflow.com/questions/14081308/why-is-the-global-keyword-not-required-in-this-case) – Jean-François Fabre Jan 02 '17 at 20:17
  • since your variable is immutable, you need to add `global`, else python would create another local reference if assigned, and logically, looks for a local reference when accessing it. – Jean-François Fabre Jan 02 '17 at 20:20
  • @Jean-FrançoisFabre My question wasn't about weather or not the global deceleration was necessary. Though I'm glad you brought my attention to it because it was informative. The example that I offered is a convoluted piece of code that I have since improved (relative to computation time) through simplifications that included removing external references. My question was about the warning itself. And the answer was more relevant than I thought. I did not know that a future release would stop executing the code. I found Jim's answer enlightening. And others may as well. – kjl Jan 03 '17 at 16:21
  • @Jean-FrançoisFabre, as a side note, the external list would be altered weather or not they were declared as global, the program failed to function as intended (to limit external writes to the first instance of the generator). That's the enlightenment that I received from the other post which answered a different question. – kjl Jan 03 '17 at 16:33

1 Answers1

7

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.

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • I tried it on Python 3.6 and it is as you said. And your idea of changing the order of the if statements worked. – kjl Jan 03 '17 at 04:31