Modifying variable outside of function

Think its a beginner question, but I do not understand why

# some lines of working code
minval = 10
maxval =22
test = 0  # a new added variable

def a_function():
    # some lines of working code
    test +=1  # new code line
    #  some lines of working code
# more lines of working
a_function()
# more working code 

now the problem in the test +=1 line show Unresolved reference ‘test’

while I can use, at least reading, other variables in functions

Where am I wrong
Thanks for help
Regards
Rainer

# some lines of working code
minval = 10
maxval =22
test = 0  # a new added variable

def a_function():
    global test
    # some lines of working code
    test +=1  # new code line
    #  some lines of working code
# more lines of working
a_function()
# more working code 

but please please don’t do this.
It’s horrid. Function side effects are horrid.

Just use the pattern (with explicit assignment)

test = 0

def f(test):
  return test + 1

test = f(test)

instead

1 Like

That’s a bit overblown. Globals have their place.

The global statement is exactly what the OP wants here.

2 Likes

I understand what Peter means, but that would not work, the variable ist outside any function. In fact I have a form with a lot of field and before the writing the values to a database the input is checked and everywhere an invalid input foud the variable should be incremeted, beforewriting to the databae the varible is checked an no writing if greater than zero and the focus is set back to the first invalid form field.

So what Chris means is OK. Do I have do define the variable a global an how

Regards
Rainer

This is considered to be an assignment statement, and since test was not declared as global inside the function, the name test becomes local throughout the function:

    test +=1  # new code line

Then, since test had not been given a value within the function prior to that attempted update, we have an Unresolved reference. We cannot update the value of a variable when the variable does not have a value.

See What are the rules for local and global variables in Python? for additional information.

That sounds like the kind of situation where I would say “please don’t use a global”.

I do agree with @Rosuav insofar as there exist situations where it would be permissible to use a global. Quick-and-dirty debugging comes to mind, because implementing a global counter is faster than putting a proper counter decorator onto a function.

But for a beginner especially, using globals allows you to hold onto poor code patterns, where a bit of dogmatic “No globals allows” mentality would push you to discover cleaner code patterns.

For what you’re describing, if I’m following it correctly, I would use a function that evaluates a form and returns one of

  • N errors found, first field with error is: …
  • 0 errors found, None

and after that proceed with either setting the focus or writing to the database.

One advantage is that since you don’t have a global state, you can’t forget to set/reset the global state.

To clarify, “update” is used here to mean utilizing one of the enhanced assignment operators, such as +=.

OK I am no beginner in programming, I do that since 50years, Assembler, PHP, C++ and others and I am not a real beginner in Python, but I new in Python GUI programming.
To Clear what I want, I have that form, each field has its validate function you can press the save button at any time, so to make it easy, before writing I call al the validate function one after the other and the I will know if everything is ok or if there still an invalid field, by klicking “save” by the user before all fields are valid.
So I thought incrementing a counter will the easiest way to do this.
Regards
Rainer

Modified my code, but test is not changed even if it should
be aware this is just a minimized example

# some lines of working code
minval = 10
maxval =22
test = 0  # a new added variable

def a_function():
     gobal test
    # some lines of working code
    test +=1  # new code line
    #  some lines of working code
# more lines of working
a_function()
# more working code 

But test is not changed

I modified my code, be aware this i just a minimized exable

# some lines of working code
minval = 10
maxval =22
global test = 0  # a new added variable

def a_function():
     global test
    # some lines of working code
    test +=1  # new code line
    #  some lines of working code
# more lines of working
a_function()
# more working code 

No more errors but test does not change
Regards
Rainer

The text you showed, throws a syntax error. It is not what you were running.

(venv) mennoh@vecht12-2:~/python/test1> python glcount.py
  File "/home/mennoh/python/test1/glcount.py", line 4
    global test = 0  # a new added variable
                ^
SyntaxError: invalid syntax

I changed it to:


# some lines of working code
minval = 10
maxval =22
test = 0  # a new added variable

print(test)

def a_function():
    global test
    # some lines of working code
    test +=1  # new code line
    #  some lines of working code
# more lines of working
a_function()
print(test)
# more working code

Which gave me as output:

(venv) mennoh@vecht12-2:~/python/test1> python glcount.py
0
1

So that works.

1 Like

Sorry to insult you, if you perceived it that way. I know I sometimes use an unfortunate word choice.

The code posted by @Mholscher and me shows how it should work with global variables. (You use global to pull a variable into a function, not when you declare the function globally.)

If you have 50 years of experience you may just want a quick way to do what you’d do in Assembler, which is fine.
There are more pythonic ways to achieve the same, without a global counter.
Specifically by using a list-, dict- or generator- comprehension. If you have a sequence of functions, python makes it very easy to test whether any of them return True, what the sum is of their returns (or how many of them return True), and what the first function is that matches a condition (such as returning True).
Such a solution would be easier for me to debug, when you run into trouble like you apparently did.
But to each their own.

First thanks for help.
Assembler ist 40 years away, but what I Iearned the last weeks, that Python is lot different from C++, even if there are a lot of C++ things work in Python too i.e. If … then …, or or for loops etc. but are going in Python more elegant and easy. Other C++ thing are not working im Python but have equivalents in Python. So please excuse. I think someone new in programming will have i easier to learn Python than some who is coming from an other language
Regards
Rainer

have you got a compelling example for a writable global varible except for quick-and dirty :face_with_open_eyes_and_hand_over_mouth:

You could fix this and make it work the way you want by adding a global statement:

test = 0  # a new added variable

def a_function():
    global test 
    test +=1  # new code line

This makes test a global variable that is accessible from anywhere in the program, whereas by default test would be considered a local variable.

The nice thing about functions is that they isolate a part of your program: you only have to bother about the inputs (the arguments assigned to the parameters in the function call) and the outputs (the return value). So if you have a bug with the output, you know the source of the bug has to be somewhere inside the function.

You can use global variables, and for small programs they’re fine. The reason experienced software developers will tell you not to use them is that if you use a global variable in the function and there’s a bug, then the source of the bug could be that global variable having a weird/wrong value in it. And since it’s global, the variable could have gotten that weird/wrong value from anywhere in the program.

This isn’t a big deal when your programs are small, but if your program is hundreds of thousands of lines long, that’s a lot of ground to cover to trace where the weird/wrong value came from.

My policy is for beginners to go ahead and use global variables when you’re starting out with small programs. You’ll eventually start coming across cases where using them is less than ideal, and you’ll see when and why you shouldn’t use them from your own experience.

Thank you for your help that made me fix my problem. And thank you for all your explanations.
An the other hand I think I have enough experiance to know the pros, cons and risks of global variables. In this case the global is if not = 0 an error sign, being set by quite a lot of validating functions, checked by other functions to proceed the program or return to input GUI, to let the user correct his input. I think thats a good reason to do this with a global. If there is a better way in Python without the global, let me know. I have not enough Python programming experience to imagine a better solution.

Regards
Rainer

The debugger is often a global mutable object, and I think there is a compelling case for that.
But I can’t currently conceive of a situation where I would leave a writable global variable in a merge request.

If you have a list of validating functions, and you could store them in a dictionary for example, you could use a pattern like

failed_fields = [field_name if not validator[field_name]()]
num_failed_fields = len(failed_fields)
if failed_fields:
  first_failed_field = failed_fields[0]

or

a_field_failed = not all(valid() for valid in validators)

It depends on how you have organised your form, the values in the fields, and the validators. If you could specify what you’re working with I could perhaps suggest a specific solution.

I could imaging a misanderstanding of the GUI workings
in case of an error only the user must be informed via the GUI, and best cursor (focus) and message are at the faulty entry
and this must be done every time before saving (GUI locked of course, some transaction behaviour)
(there may be modified flags at the fields and Validators in the GUI, for performance)
so there is no need at all to remember a GUI input error, I think :rofl:

OK there are three field mandatory name(min 3 max 40 chars), password (min 6, max 30), email (nin 4, max 40 +a valid email) mandatory, an the optional fields age betwen 10 and 99, gender m/f/o and address max 40 chars.
each fiel has ist own check function, and a user info field whats wrong or OK, as long the conditon is ok, the cursor is set back into the field. I did not manage it to disable the save button while not every filed is valid in case of the optional fields.
So it is posible to click the save button any time independent.
My solution was when save is clicked to set the global test var to 0, call every check function on after the other and if an error is found set the cursor back in the field, notifying the user and increment the test var, So if all field s avalid the test var ist still zero and I can insert everything into a database. If it ist not 0, the user is back in the form, noticed whats still wrong, Thats go es as long as not every field is valid.
I everything is valid, the data are saved to the database, the form is cleared, the focus set ti the firts field. That work fine now. My only problem was makeing the global work and now a big discussion came out of it. If someone is interested in the complete code, let me know, I will post it here

Regards
RAiner