The relevant code here is
res = m
def help(a, b):
print(res)
res = min(res, a*b) # may or may not be commented out
This is not doing what you think it is.
Let's go through this line-by-line:
res = m: this defines the variable res, with value m, which lives in the main function
def help(a, b): begins a function definition. Within the help function, you are able to define entirely new variables which are insulated from the variables in main
print(res): this prints the value of variable res. To find the value of res, Python will first look in help function a variable named res. If there is none, it will search the main function (i.e. the parent scope) for a variable named res. (If there were to be none there, it would continue to search higher and higher scopes.) As it turns out, in your example, whether or not there is a variable named res in the help function depends on whether or not line 4 is commented out!
res = min(res, a*b): This does not do what you think it does. What you want it to do is to change the variable value of the res variable in the main function. However, Python will instead create a new variable res within the help function and set its value to min(res, a*b).
This is why you are getting an UnboundLocalError. Because when line 4 is uncommented, then print(res) refers to the variable named res in the help function, not the main function. But when line 4 is commented out, there is no res variable in the help function, so print(res) instead uses the variable in the main function.
So, how to fix it? Actually pretty simple, just change the code to:
def help(a, b):
nonlocal res
print(res)
res = min(res, a*b)
The nonlocal statement tells Python, "hey, the res variable is coming from an outer scope".