1

This code

def reportRealDiagnostics():

        ranks = 0
        class Rank: 
            def __init__(self):
                global ranks
                ranks += 1
        rank = Rank()

reportRealDiagnostics()

produces

NameError: global name 'ranks' is not defined

I am sure that this is all what you need to answer the question.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
Val
  • 1
  • 8
  • 40
  • 64
  • "I am sure that this is all what you need to answer the question." It would have been better to **ask a question**, starting with a question word like "why" or "how", and ending with a question mark (`?`). – Karl Knechtel Sep 11 '22 at 09:40

2 Answers2

3

When you use global ranks it looks for ranks in the global scope not in enclosing scope, so you get that error. The ranks you've defined is part of the enclosing scope.

In Python3 this has been resolved and you can modify ranks by using the nonlocal keyword:

def reportRealDiagnostics():
        ranks = 0
        class Rank: 
            def __init__(self):
                nonlocal ranks
                ranks += 1
        rank = Rank()

reportRealDiagnostics()

In Python2 you can define it as a function attribute:

def reportRealDiagnostics():
        class Rank: 
            def __init__(self):
                reportRealDiagnostics.ranks += 1
        rank = Rank()
reportRealDiagnostics.ranks = 0
reportRealDiagnostics()

There are some other alternatives too: nonlocal keyword in Python 2.x

Community
  • 1
  • 1
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • It is important to remember that the second option is not semantically the same. It puts `ranks` in the global scope, it is just hidden in the function's namespace. Multiple invocations of reportRealDiagnostics will use the same variable. It still might be OK. – Evan Nov 09 '13 at 15:23
  • There is a more serious problem than just global scope with python 2.x. The problem is that **you must initialize the function-local variables every time before you call the function.** This defeats the whole idea of having local variables. – Val Nov 09 '13 at 15:47
  • @Val If you're talking about [this](http://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value), then this is not a issue related to py2.x, it works similarly in py3.x as as well. I wouldn't call it a issue as well. – Ashwini Chaudhary Nov 09 '13 at 17:24
  • Wait, you say that option is intended for Python2. Who cares about it regarding Py3? – Val Nov 09 '13 at 18:26
  • My point was that you better declare a global variable as per normal rather than do it and initialize it properly at every call of you function. The point (of the very function) is that you initialize the `ranks` variable to a proper value in the parent function. Caller should not do that. He better not beware that such variable even exists. I have checked that you can declare the variable easily by simply defined in global `reportRealDiagnostics` function. You should have `def f(): global r; r = 1; class C: __init__ global r; access(r)` – Val Nov 10 '13 at 12:47
  • @Val Using `globals` like that is usually not recommended, better use a `Class`. Plus when you import your function to some other module then `global r` in `f()` is still going to point to the global namespace in original file, it won't create or access a global in the current module. – Ashwini Chaudhary Nov 10 '13 at 12:53
0

You should use variable as nonlocal:

nonlocal ranks
Danil Speransky
  • 29,891
  • 5
  • 68
  • 79