UnboundLocalError: local variable 'sumOfOdd' referenced before assignment in Python3 - python

I'm trying to run this code:
number = input("Number: ")
valid = False
sumOfOdd = 0
def validation(credit_num):
for i in range(len(credit_num)):
if i % 2 != 0:
sumOfOdd += i
def main():
print(f"Your credit card number is {number}, it's third digit is {number[2]}")
print(f'sum of odds: {sumOfOdd}')
validation(number)
main()
But I get this error:
Traceback (most recent call last):
File "credit.py", line 15, in <module>
validation(number)
File "credit.py", line 8, in validation
sumOfOdd += i
UnboundLocalError: local variable 'sumOfOdd' referenced before assignment
I'm able to run, but when I input any number it gives me this error

This error occurs because the variable sumOfOdd is not accessible from within the function. You could declare the variable global in the function, but you should be careful using the global statement.
In my opinion, a better way to do this is to supply sumOfOdd as an argument to the function and return the updated variable:
def validation(credit_num, sumOfOdd):
for i in range(len(credit_num)):
if i % 2 != 0:
sumOfOdd += i
return sumOfOdd
validation(number, 0)
# Returns the correct sum.
Or, if you know that the sumOfOdd should always be initialized by zero, you could define the variable locally:
def validation(credit_num):
sumOfOdd = 0
for i in range(len(credit_num)):
if i % 2 != 0:
sumOfOdd += i
return sumOfOdd

Here's a working version of your code.
Note that it now iterates through credit_num as for num in credit_num. If you use for i in range(len(credit_num)) you are iterating through a list of indexes and would need to use if int(credit_num[i]) % 2 != 0, reason being that range(N) returns a list [0, 1, 2... N-1] where for num in credit_num iterates through [1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4] if your input string was 1111222233334444
number = input("Number: ")
valid = False
sumOfOdd = 0
def validation(credit_num):
global sumOfOdd
for num in credit_num:
if int(num) % 2 != 0:
sumOfOdd += 1
def main():
print(f"Your credit card number is {number}, it's third digit is {number[2]}")
print(f'sum of odds: {sumOfOdd}')
validation(number)
main()
Note that validation(number) is called in global scope along with main(), hence the global sumOfOdd declaration inside to allow def validation to gain access to that variable.
A different way to write this code to make it more readable would be:
if __name__ == "__main__":
number = input("Number: ")
valid = False
sumOfOdd = 0
def validation(credit_num):
sumOfOddToReturn = 0
for num in credit_num:
if int(num) % 2 != 0:
sumOfOddToReturn += 1
return sumOfOddToReturn
sumOfOdd = validation(number)
print(f"Your credit card number is `{number}`, its third digit is `{number[2]}`.")
print(f'sum of odds: {sumOfOdd}')

Related

Python splitting code into functions [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Parameter vs Argument Python [duplicate]
(4 answers)
Closed 5 years ago.
Sorry about the length of this but I figured more info is better than not enough!!
I'm trying to split the (working) piece of Python code into functions to make it clearer / easier to use but am coming unstuck as soon as i move stuff into functions. It's basically a password generator which tries to only output a password to the user once the password qualifies as having a character from all 4 categories in it. (Lowercase, uppercase, numbers and symbols).
import random
import string
lowerasciis = string.ascii_letters[0:26]
upperasciis = string.ascii_letters[26:]
numberedstrings = str(1234567809)
symbols = "!#$%^&*()[]"
password_length = int(raw_input("Please enter a password length: "))
while True:
lowerasscii_score = 0
upperascii_score = 0
numberedstring_score = 0
symbol_score = 0
password_as_list = []
while len(password_as_list) < password_length:
char = random.choice(lowerasciis+upperasciis+numberedstrings+symbols)
password_as_list.append(char)
for x in password_as_list:
if x in lowerasciis:
lowerasscii_score +=1
elif x in upperasciis:
upperascii_score +=1
elif x in numberedstrings:
numberedstring_score +=1
elif x in symbols:
symbol_score +=1
# a check for the screen. Each cycle of the loop should display a new score:
print lowerasscii_score, upperascii_score, numberedstring_score, symbol_score
if lowerasscii_score >= 1 and upperascii_score >= 1 and numberedstring_score >= 1 and symbol_score >=1:
password = "".join(password_as_list)
print password
break
And here is my attempt at splitting it. When i try to run the below it complains of "UnboundLocalError: local variable 'upperascii_score' referenced before assignment" in the scorepassword_as_a_list() function
import random
import string
lowerasciis = string.ascii_letters[0:26]
upperasciis = string.ascii_letters[26:]
numberedstrings = str(1234567809)
symbols = "!#$%^&*()[]"
password_length = int(raw_input("Please enter a password length: "))
lowerasscii_score = 0
upperascii_score = 0
numberedstring_score = 0
symbol_score = 0
password_as_list = []
def genpassword_as_a_list():
while len(password_as_list) < password_length:
char = random.choice(lowerasciis+upperasciis+numberedstrings+symbols)
password_as_list.append(char)
def scorepassword_as_a_list():
for x in password_as_list:
if x in lowerasciis:
lowerasscii_score +=1
elif x in upperasciis:
upperascii_score +=1
elif x in numberedstrings:
numberedstring_score +=1
elif x in symbols:
symbol_score +=1
# give user feedback about password's score in 4 categories
print lowerasscii_score, upperascii_score, numberedstring_score, symbol_score
def checkscore():
if lowerasscii_score >= 1 and upperascii_score >= 1 and numberedstring_score >= 1 and symbol_score >=1:
return 1
else:
return 0
def join_and_printpassword():
password = "".join(password_as_list)
print password
while True:
genpassword_as_a_list()
scorepassword_as_a_list()
if checkscore() == 1:
join_and_printpassword()
break
The primary issue here is that you need to keep track of the scope of the various variables that you're using. In general, one of the advantages of splitting your code into functions (if done properly) is that you can reuse code without worrying about whether any initial states have been modified somewhere else. To be concrete, in your particular example, even if you got things working right (using global variables), every time you called one of your functions, you'd have to worry that e.g. lowerassci_score was not getting reset to 0.
Instead, you should accept anything that your function needs to run as parameters and output some return value, without manipulating global variables. In general, this idea is known as "avoiding side-effects." Here is your example re-written with this in mind:
import random
import string
lowerasciis = string.ascii_letters[0:26]
upperasciis = string.ascii_letters[26:]
numberedstrings = str(1234567809)
symbols = "!#$%^&*()[]"
def genpassword_as_a_list(password_length):
password_as_list = []
while len(password_as_list) < password_length:
char = random.choice(lowerasciis+upperasciis+numberedstrings+symbols)
password_as_list.append(char)
return password_as_list
def scorepassword_as_a_list(password_as_list):
lowerasscii_score = 0
upperascii_score = 0
numberedstring_score = 0
symbol_score = 0
for x in password_as_list:
if x in lowerasciis:
lowerasscii_score +=1
elif x in upperasciis:
upperascii_score +=1
elif x in numberedstrings:
numberedstring_score +=1
elif x in symbols:
symbol_score +=1
# give user feedback about password's score in 4 categories
return (
lowerasscii_score, upperascii_score, numberedstring_score,
symbol_score
)
def checkscore(
lowerasscii_score, upperascii_score, numberedstring_score,
symbol_score):
if lowerasscii_score >= 1 and upperascii_score >= 1 and numberedstring_score >= 1 and symbol_score >=1:
return 1
else:
return 0
def join_and_printpassword(password_as_list):
password = "".join(password_as_list)
print password
password_length = int(raw_input("Please enter a password length: "))
while True:
password_list = genpassword_as_a_list(password_length)
current_score = scorepassword_as_a_list(password_list)
if checkscore(*current_score) == 1:
join_and_printpassword(password_list)
break
A few notes on this:
Notice that the "score" variables are introduced inside the scorepassword_as_list function and (based on the scoping rules) are local to that function. We get them out of the function by passing them out as a return value.
I've used just a bit of magic near the end with *current_score. Here, the asterisk is used as the "splat" or "unpack" operator. I could just as easily have written checkscore(current_score[0], current_score[1], current_score[2], current_score[3]); they mean the same thing.
It would probably be useful to read up a bit more on variable scoping and namespaces in Python. Here's one guide, but there may be better ones out there.

NameError: name 'recPower' is not defined

I am working on a assignment and am encountering this error. NameError: name 'recPower' is not defined
Write a recursive function called pow(base, power) that takes in two numbers. First number is a base and the second number is a power. The function will return the number raised to the power. Thus, if the number is 2 and the power is 4, the function will return 16. (75 points).
Write a main() function that asks for a number and a power. Then calls the recursive function created in step 1 (15 points).
DO NOT use the algorithm on page 432 of your book:
def: recPower (a, n):
if n == 0:
return 1
else:
factor = recPower (a, n//2)
if n%2 == 0:
return factor * factor
else:
return factor * factor * a
My current code is as follows
def main():
a=input("enter base :")
n=input("enter power :")
print ("Total = ",recPower(a,n))
main()
def recPower (a,n):
if n == 0:
return 1
else:
return a*recPower(a,n-1)
`
The error I get when I run it is :
Traceback (most recent call last):
File ".py", line 7, in
main()
File ".py", line 5, in main
print ("Total = ",recPower(a,n))
NameError: name 'recPower' is not defined
Functions are stored in identifiers. You have to define it first. Try this one:
def recPower(a, n):
if n == 0:
return 1
else:
return a * recPower(a, n - 1)
def main():
a = int(input("enter base :"))
n = int(input("enter power :"))
print ("Total = ", recPower(a, n))
main()
Define your 'run' function after 'recPower'.
As also mentioned you need to convert the strings that are returned from input() into integers or floats, using either int() or float(). When you try to operations like division you'll get TypeError exceptions.
write your method above the main code, because if you write at under the main code method is undefinied
functions must be defined before any are used.
try this code
def recPower(a, n):
# or just a, n = int(a), int(n) is fine
if isinstance(a, str):
a = int(a)
if isinstance(n, str):
n = int(n)
if n == 0:
return 1
else:
return a * recPower(a, n - 1)
def main():
a = input("enter base :")
n = input("enter power :")
print ("Total = ", recPower(a, n))
main()

Random number generator and validator

This is my code for a gtin-8 number generator
barcode = []
inputChoice = 0
inputChoice = 1
checkNumber = 0
placeHolder = 0
def generate():
generate = 0
for i in str(Userinput):
barcode.append(int(i))
print(barcode)
for i in range (0,6,2):
generate += barcode[i] *3
print('Generate is now ',generate)
print(generate)
def checkNumber():
for i in str(Userinput):
checkNumber += int(i)
placeHolder += int(i)
checkNumber = round(checkNumber, -1)
checkNumber = (checkNumber - placeHolder) % 10
return(checkNumber)
def check():
jk = 0
def main():
inputChoice=0
while inputChoice !=9 and inputChoice !=1 and inputChoice!=2:
inputChoice=int(input("chose 1 to get GTIN,2 to check,9 to exit\n"))
Userinput = (input("input the barcode \n"))
if inputChoice==1 :
if len(Userinput) !=7:
print("make sure you inputted 7 inegers")
if inputChoice == 2:
if len(Userinput) !=8:
print("Make sure you input 8 integers")
else:
generate(Userinput)
return(Userinput)
Userinput = main()
generate()
checkNumber()
I have made a function called check number, generate and main but when I run a code it gives me this error:
TypeError: generate() takes 0 positional arguments but 1 was given
I am unsure why this is the case, jk = 0 is there as I have not finished that function and I am just using it as a placeholder.
works fine after adding *args, than we get
UnboundLocalError: local variable 'checkNumber' referenced before assignment
so add default args in the flag of checkNumber()
def generate(*args): #<<<< edit
generate = 0
for i in str(Userinput):
barcode.append(int(i))
print(barcode)
for i in range (0,6,2):
generate += barcode[i] *3
print('Generate is now ',generate)
print(generate)
def checkNumber(checkNumber=0, placeHolder=0): #<<<< edit
for i in str(Userinput):
checkNumber += int(i)
placeHolder += int(i)
checkNumber = round(checkNumber, -1)
checkNumber = (checkNumber - placeHolder) % 10
return(checkNumber)
that its works finaly result with 1515155155151 as barcode:
chose 1 to get GTIN,2 to check,9 to exit
2
input the barcode
1515155155151
Make sure you input 8 integers
[1, 5, 1, 5, 1, 5, 5, 1, 5, 5, 1, 5, 1]
Generate is now 3
Generate is now 6
Generate is now 9
9
Ok you asked for feedback so here we go...
Point #1: dont use globals when you dont need them. Hint : you can write huge (10+klocs) programs without a single global (talking about globals that are modified or reassigned during execution of course - pseudo-constants etc are ok). Practicaly, this starts by writing pure functions - functions that take arguments, return results, and for which the same set of arguments will always produce the same results
Point #2: respect the language's usual coding conventions (cf pep8 for Python)
Point #3: learn the language's idioms - in your example,
use of str.format()
use of list comprehensions or generator expressions instead of for loops where it makes sense,
a main() function that is really a main function and is guarded by a if __name__ == "__main__": check)
Here's an example of what your code could look like once those points are fixed:
def generate(source):
barcode = [int(c) for c in source]
result = sum(barcode[i] * 3 for i in range(0, 6, 2))
return result, barcode
def check_number(source):
placeholder = checksum = sum(int(i) for i in source)
checksum = round(checksum, -1)
checksum = (checksum - placeholder) % 10
return checksum
def check(what):
jk = 0
def main():
choice = 0
while True:
choice = input("chose 1 to get GTIN, 2 to check, 9 to exit\n").strip()
try:
choice = int(choice)
if choice not in (1, 2, 9):
raise ValueError
except ValueError:
print("Invalid value '{}'".format(choice))
continue
if choice == 9:
return
while True:
source = input("input the barcode \n").strip()
# source should contain only digits
try:
int(source)
except ValueError:
print("Make sure you entered only integers")
continue
if choice == 1 and len(source) != 7:
print("Make sure you entered 7 integers")
continue
elif choice == 2 and len(source) != 8:
print("Make sure you entered 8 integers")
continue
else:
# ok, valid input
break
if choice == 1:
result, barcode = generate(source)
print("barcode : {}.".format(barcode))
print("result : {}".format(result))
elif choice == 2:
raise NotImplementedError("check is not yet implemented")
if __name__ == "__main__":
main()

Python TypeError: Find_Number() missing 1 required positional argument: 'limitdivision'

TypeError: Find_Number() missing 1 required positional argument: 'limitdivision'
I still not get why my code is error:
def main():
obj = FindMaxNumber()
result = obj.Final_Result(500)
print("The Final Result is {} ". format(result))
class FindMaxNumber():
delf Find_Division(self, num):
self.num = num
if num%2==0:
num = num/2
count = 0
division = 1
while num%2==0:
count+=1
num = num/2
division=division*( count + 1 )
div = 3
while num != 1:
count = 0
while num%div==0:
count+=1
num = num/div
division = division( count + 1)
div+=2
return division
def Find_Number(self, limitdivision):
self.limitdivision = limitdivision
n = 1
inum , fnum = FindMaxNumber.Find_Division(n) , FindMaxNumber.Find_Division(n+1)
while inum*fnum < limitdivision:
n+=1
inum , fnum = fnum , FindMaxNumber.Find_Division(n+1)
return inum
def Final_Result(self , index):
self.index = index
num = FindMaxNumber.Find_Number(index)
final = (num(num+1)/2)
return final
if __name__=="__main__": main()
Can anyone tell what I support to do with this code?
You are calling the method on the class. You probably wanted to call it on self instead:
num = self.Find_Number(index)
This goes for all FindMaxNumber. references in your methods; call methods on the instance unless you have a very specific reason to call them on the class instead, in which case you need to pass in an instance as the first argument, explicitly.

why am I getting this python syntax indexerror

I am new to python and programming in general. I have received many syntax errors in my program. most have been Index errors. When I run it now what I get is:
"Traceback (most recent call last):
File "C:\Python33\HW3 playing around.py", line 133, in <module>
Main()
File "C:\Python33\HW3 playing around.py", line 32, in Main
EmployeeNumbers()
File "C:\Python33\HW3 playing around.py", line 69, in EmployeeNumbers
Sal[Index] = float(input("Enter Employee salary here: "))
IndexError: list assignment index out of range"
I have no idea how to solve both this error and many others that this program has, any help would be appreciated.
-Jacob
# Description: This program will Calculate the Average, Maximum, and Minimum Salaries of employees
#Declare Variables
EmpNum = 0
SalAVG = 0
Index = 0
SalTot = 0
# Start Main
def Main():
# Get Number of employees
EmpNum = int(input("Enter the number of employee's here: "))
if EmpNum <=0:
print("Please enter positive number")
while Index < EmpNum:
# Call EmployeeNames
global Name
global Index
global SalTot
Name = [Index]
EmployeeNames()
# Call EmployeeNumbers
global Sal
Sal = [Index]
EmployeeNumbers()
# Calculate SalTot
SalTot = SalTot + Sal[Index]
# Increase Index
Index = Index + 1
# Calculate and output AVG
SalAVG = SalTot / Index
print("The average salary is $", SalAVG)
# Call and output Maximum
Maximum()
print("The highest paid employee is ", EmpName, " With a salary of $")
# Call and output Minimum
global Temp
global Switch
Minimum
print("The Lowest paid employee is ", EmpName, " With a salary of $")
# Arrays
# EmployeeNames array
def EmployeeNames():
# Bind global parts
global Name
global Index
# Run EmployeeNames
Name[EmpNum] = str(input("Enter employee name here: "))
# EmployeeNumbers Array
def EmployeeNumbers():
#Bind Global parts
global Sal
#Run EmployeeNumbers
Sal[Index] = float(input("Enter Employee salary here: "))
if Sal[EmpNum] > 200000:
print("Please enter lower salary")
Sal[EmpNum] = float(input("Enter Employee salary here: "))
if Sal[EmpNum] < 0:
print("Please enter positive number")
Sal[EmpNum] = float(input("Enter Employee salary here: "))
# Maximum array
def Maximum():
# Bind global parts
global Temp
global Switch
global Name
Index = 1
Temp = 0
Switch = 1
while Switch > 0:
Index = 1
if Sal[Index] > Sal[Index + 1]:
# Call NameSwitch
global TempName
global Name
NameSwitch()
Temp = Sal[Index]
Sal[Index] = Sal[Index + 1]
Sal[Index + 1] = Temp
Switch = Switch + 1
Index = Index + 1
Switch = 1
# Minimum array
def Minimum():
# Bind global parts
global Temp
global Switch
global Name
Index = 1
Temp = 0
Switch = 1
while Switch > 0:
Index = 1
if Sal[Index] < Sal[Index + 1]:
# Call NameSwitch
global TempName
global Name
NameSwitch()
Temp = Sal[Index]
Sal[Index] = Sal[Index + 1]
Sal[Index + 1] = Temp
Switch = Switch + 1
Index = Index + 1
Switch = 1
# NameSwitch array
def NameSwitch():
#Bind global parts
global TempName
global Name
TempName = ""
TempName = Name[Index]
Name[Index] = Name[Index + 1]
Name[Index + 1] = TempName
Main()
I'm not going to fix your code, but your problem can be simplified to:
>>> some_list = []
>>> some_list[0] = "Hello World"
IndexError: list assignment index out of range
To fix it, you need to either start the list with an initial size:
>>> some_list = [None]
>>> some_list[0] = "Hello World"
Or append to the empty list:
>>> some_list = []
>>> some_list.append("Hello World")
Your major problem stems from the use of global variables. Instead of creating global variables, define your function with the variables as arguments like this:
def Maximum(Temp,Switch,Name):
Then call the function like this
Maximum(Temp,Switch,Name)
That way you can keep track of everything your function will need when defining it.
Back to your error, the problem is that Index is not defined in the function. recreate the function header like so:
def EmployeeNumbers(sal,index):
and in main, call it like this:
EmployeeNumbers(sal, index)
Last, define all of your variables inside main, so you do not need to pass them into main when you call it.

Categories

Resources