You seem to be trying to get Python to guess which functions are supposed to be global and which local based on their names. Python doesn't do that. If you assign to a variable in a function, and you want that assignment to be global, you need a global statement at the top of the function:
def verify_nums():
global globhours
global blograte
globhours = hours
globrate = rate
# ...
Also, globhours = globhours doesn't do anything useful—and, in fact, it causes a problem. If you global globhours in that function as well, the statement is meaningless. Without that, you're creating a local variable, and assigning it… the value of that local variable that doesn't exist yet.
Anyway, if you add the right global declarations to all of your functions, they will work, but it won't be a great design.
You really don't need any global variables here. If you think about values rather than variables, everything gets a lot easier.
Your verify_nums function needs to work on two values. So just pass those values in as parameters. And it needs to return two values—that's easy, you already did that part.
Now the caller has to store those two values that it returned, so it can pass them to the calc function. Which can also take two values as parameters.
Putting that all together:
def verify_nums(hours, rate):
try:
numhours = float(hours)
numrate = float(rate)
return numhours, numrate
except:
print("You must provide numbers")
def calc(hours, rate):
if hours > 40:
base = 40 * rate
ot = (hours - 40) * (rate * 1.5)
pay = base + ot
print(pay)
else:
pay = rate * hours
print(pay)
globhours = input("Enter hours worked: ")
globrate = input("Enter hourly rate: ")
hours, rate = verify_nums(globhours, globrate)
calc(hours, rate)
One problem left: what happens if there's an error with the user's input? Inside verify_nums, you handle the error with an except:, then you print a message and do nothing. That means you return None. So, when the caller tries to do hours, rate = None, it's going to get an error, which you're not handling. And you can't just carry on without values. What can you do?
More generally "return a pair of numbers, or return None" is a confusing contract for a function to fulfill. How do you use that function? With a whole lot of ugly type-checking. But "return a pair of numbers, or raise an exception" is a perfectly good contract. How do you use that function? With a simple try.
That's why it's better to put the exception handling in exactly the right place where you can deal with it. You want to skip calling calc if there's an error, so the except has to be where you call calc.
def verify_nums(hours, rate):
numhours = float(hours)
numrate = float(rate)
return numhours, numrate
def calc(hours, rate):
if hours > 40:
base = 40 * rate
ot = (hours - 40) * (rate * 1.5)
pay = base + ot
print(pay)
else:
pay = rate * hours
print(pay)
try:
globhours = input("Enter hours worked: ")
globrate = input("Enter hourly rate: ")
hours, rate = verify_nums(globhours, globrate)
except ValueError:
print("You must provide numbers")
else:
calc(hours, rate)
Another improvement you might want to consider: Have calc return the pay, instead of printing it, and make the caller print the value it returns.
verify_numsfirst.