Why can't I set a global variable within a function?

Why can’t I define “grade = F” outside the function?

Here is my code:

grade = "F"
def grade_converter(gpa):
  if gpa>=4.0:
    grade = "A"
  elif gpa>=3.0:
    grade = "B"
  elif gpa>=2.0:
    grade = "C"
  elif gpa>=1.0:
    grade = "D"
  return grade

If my input is greater than or equal to 1.0, then the result will be okay. But, if my input is less than 1, there will be the error like:

Traceback (most recent call last):
File “script.py”, line 13, in
print(grade_converter(0.8))
File “script.py”, line 11, in grade_converter
return grade
UnboundLocalError: local variable ‘grade’ referenced before assignment

4 Likes

Defining grade inside the function works well, but if I define grade before defining the function, I get a name error. Why?

Global variables can be accessed from within functions, but we cannot set them without explicitly naming them as global inside the function.

foo = 0
def bar():
  global foo
  foo += 1

That may have some bearing on your case.

28 Likes

Hi @husainritonga,

From what I’ve read about writing clean code and assigning values to global variables, the main reason (besides the fact that it results in an UnboundLocalError and breaks your code) not to set grade to “F” here is that there is no compelling reason to do so, and it makes the code just that slight bit more confusing to all who might have to read it subsequently. Whoever tries to rewrite your code later for whatever reason will have to ask “Why is the default grade “F”? Is there a reason for this?”

The only reason to do it in the first place is that it (potentially) saves one line of code (we’re overlooking the fact that it makes the code snippet non-functional). And that’s a reason, but not a compelling one.

Does it matter on 10 lines of code if there’s a moment’s hesitation on the part of whoever looks at your code later? On 10 lines, no. But multiply that out by function after function, line after line - you write a simple 1000-line program (okay, that’s not sooo simple, but you get what I’m saying), and if you’re careless about how the code is written after every step, suddenly you have 100 different places where anyone refactoring or otherwise dealing with your code has to stop and say “Why did the coder do this?”

They say that most coders/developers spend over half their time reading code rather than writing it. Sounds plausible to me.

So think of the generations to come who will need to calculate their grades using your function!

Have a good one, and happy coding everyone.

17 Likes

I know one way to change global variable inside a function is to use the keyword ‘global’ and define the variable you intend to use. Example in this case:
def grade_converter(gpa):
global grade

Doing it this way will return the grade value when gpa is below 1.0. But I too don’t understand why it gives error. grade is defined globally, so if no condition is met, it should access the value defined globally.
Maybe some experienced programmer here can answer this.

You are right but in his case, if no condition is met, then grade is never set and the function should use the globally defined grade, which it doesn’t in this case. And that’s confusing me.

I had that exact question : “Why is the default grade “F”? Is there a reason for this?”
Thanks for your answer, even I’m not totally sure I get it, at least It is a start.

1 Like

Hi @digitalplayer39038,

The default grade is "F" in this exercise, because the if and elif blocks have previously handled all the other possibilities. If the grade is not "A", "B", "C", or "D", then "F" is the only possibility that remains.

Though the instructions do not ask you to do it this way, you could rewrite the function so that the default is "A", as follows:

 def grade_converter(gpa):
  if gpa < 1.0:
    grade = "F"
  elif gpa < 2.0:
    grade = "D"
  elif gpa < 3.0:
    grade = "C"
  elif gpa < 4.0:
    grade = "B"
  else:
    grade = "A"
  return grade

Link to exercise: Python: Control Flow: Else If Statements

Last edited on November 11, 2019 to provide a link to the exercise

4 Likes

dont know why but your answer is like using other planet’s language, what is foo, why there is +=1 , global is a syntax?,
sr but your answer alw confuse me.

1 Like

It is a generic, or pseudo variable name. Note that it is defined in global scope (not inside the function).

That is a step that changes the value of foo inside the function.

Yes, it is Python syntax, and more importantly a necessary declaration inside a function if we are going to mutate a variable in global scope.

>>> foo = 0
>>> def bar():
	foo += 1

	
>>> bar()
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    bar()
  File "<pyshell#38>", line 2, in bar
    foo += 1
UnboundLocalError: local variable 'foo' referenced before assignment
>>> def bar():
	global foo
	foo += 1

	
>>> bar()
>>> foo
1
>>> 
2 Likes

"When a parameter has the same name as a variable defined outside, instead of the function using the variable defined outside, it will only reference the value that was passed to the parameter. So, parameters will be used over variables of the same name within a function. "

I guess here the rule is similar although “grade” is not a parameter?

I believe, if you assign values to any variable inside function, it is treated as a local variable. So, it is treating ‘grade’ as local variable instead of global one. Try changing the variable name while assignment inside function as following:

grade = "F"
def grade_converter(gpa):
  if gpa>=4.0:
    gr = "A"
  elif gpa>=3.0:
    gr = "B"
  elif gpa>=2.0:
    gr = "C"
  elif gpa>=1.0:
    gr = "D"
  return grade
print(grade_converter(0)) #output F

Apart from assigning values, if you perform any other operation it works fine.
Example:
It works fine…

y=10
def experiment(x):
 if x==10:
   y
 return y
print(experiment(0))

This gives same error…

y=10
def experiment(x):
 if x==10:
   y=1
 return y
print(experiment(0))

2 Likes

So true what you said at the end there. Setting a F as default reflect creates an anomaly in the rules you just wrote evaluate numbers. keep things simple, but no more simpler than it is.

Mtf but I don’t understand for example how this code works without defining a global variable:

header_string = "Our special is " 
 
def create_special_string(special_item):
  return header_string + special_item + "."
print(create_special_string("grapes"))

That’s because you are not attempting to reassign the variable. The code is returning a new expression.

The program correctly returns F for me using your syntax.
grade = “F”
def grade_converter(gpa):
if gpa>=4.0:
grade = “A”
elif gpa>=3.0:
grade = “B”
elif gpa>=2.0:
grade = “C”
elif gpa>=1.0:
grade = “D”
gpa = 0.88
return grade

Defining the grade variable inside the Function with an ‘else’ statement would be best. Whenever you call the function grade_converter(), the grade variable it is limited to is the local variable defined in the Function and it does not reference the value of the Global variable where grade = “F”. So the best way to write the function is with an else statement.

def grade_converter(gpa):
  if gpa>=4.0:
    grade = "A"
  elif gpa>=3.0:
    grade = "B"
  elif gpa>=2.0:
    grade = "C"
  elif gpa>=1.0:
    grade = "D"
  else:
    grade = "F"
  return grade

print(grade_converter(0.5))