The problem here is in how Python binds names to variables.
Any time you write an assignment in a function (something like a = b or a += b), Python will bind that name locally for the entire function scope. This means that any variables with that name declared outside the function are ignored.
For example:
a = 1 # This variable is ignored.
def foo():
print(a) # "a" hasn't been defined yet!
a = 2 # This causes "a" to bind to a local variable.
This will produce an UnboundLocalError at the print statement because Python sees that a is assigned to later in the function, and binds it locally, ignoring the variable you defined outside the function. Since a is only defined after the print statement, you get an error.
This can be very confusing because removing the a += 2 line will cause the print statement to work as expected!
The solution is to explicitly tell Python not to bind the name locally. This can be done with the global and nonlocal keywords, e.g.:
a = 1
def foo():
nonlocal a # or: global a
print(a)
a += 2
global tells Python to bind the name in the module's global scope, while nonlocal (introduced in Python 3) tells Python to bind to the enclosing scope (for example, if you define a function inside a function).
There's a nice explanation of this (with examples) in the documentation :-)
Once we understand these rules, we can see that your first example fails because you're trying to increment a variable that doesn't yet exist. output += 1 is equivalent to output = output + 1, which triggers local name binding.
On the other hand, your second example doesn't trigger the error because you're not assigning to output (you're mutating it instead), so it will bind to the global variable that you defined.