2
counter = 0

def addCounter():
    counter = counter + 1
    return counter

UnboundLocalError: local variable 'counter' referenced before assignment.

I'm trying to make a counter count every time this function runs. I've tried passing the counter variable in as a parameter as well, but that doesn't work either.

S3DEV
  • 8,768
  • 3
  • 31
  • 42
  • you should use `global counter` –  Jan 21 '20 at 08:28
  • 2
    Another option is to wrap the function in a **class**, and have `counter` as a class variable - which will be accessible to all functions in the class. – S3DEV Jan 21 '20 at 08:29
  • 2
    Definitely preferable to use a class and class variables over globals. – Jason Chia Jan 21 '20 at 08:31
  • 1
    Does this answer your question? [Function not changing global variable](https://stackoverflow.com/questions/12665994/function-not-changing-global-variable) – marke Jan 21 '20 at 08:34

2 Answers2

4

You need:

counter = 0

def addCounter():
     global counter
     counter = counter + 1
     return counter

Explanation: in Python, the declaration of inner variables is implicit, an assignment automatically declares the values on the left-hand side, however that declaration is always in the local scope. That's why if you write this:

counter = 0
def addCounter():
    return counter

it will work fine but as soon as you add an assignment

counter = 0
def addCounter():
    counter += 1
    return counter

it breaks: the assigment adds an implicit local declaration. global overrides this, although it requires that the global exist beforehand, it does not create a global, it just tells the function that this is a global variable it can reassign to.

I've tried passing the counter variable in as a parameter as well, but that doesn't work either.

Indeed not. Python's evaluation strategy is sometimes called "pass by sharing" (or "pass reference by value") which is technically "pass by value" but that term gets a bit confusing as the values in this case are references, the references are copied but the objects referred to are not, and thus the end-behaviour diverges from the normal expectations of "pass by value" expectations.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
Sociopath
  • 13,068
  • 19
  • 47
  • 75
2

Using a class rather than global:

Another way to handle (not use) global variables is to wrap the functions and variables you wish to be global in a class.

While this is a little heavy for this specific case - classes add a host of functionality and flexability to the project. (Personally) highly recommended.

For example:

class Processor():
    """Class container for processing stuff."""

    _counter = 0

    def addcounter(self):
        """Increment the counter."""
        # Some code here ...
        self._counter += 1

# See the counter incrementing.
proc = Processor()
proc.addcounter()
print(proc._counter)
proc.addcounter()
print(proc._counter)

Output:

1
2
S3DEV
  • 8,768
  • 3
  • 31
  • 42