How can I get eval() to execute a function I define? [Python] - python-3.x

I have some code that I need to evaluate in python 3.4.1
def foo(bar):
somecode
def myFunction(codeInString):
eval("foo(" + codeInString + ")")
But every time I try to evaluate it, I get an error that says
NameError: name 'foo' is not
When I use 'q Patrick m 1880 1885 2' as input, it should give me back a list of three tuples. Instead I get
File "C:\...\Project 1\names.py", line XXX, in BBNInput
return(eval("getBirthsByName(" + query + ")"))
File "<string>", line 1, in <module>
NameError: name 'getBirthsByName' is not defined
I defined tiny_names.csv below the code block
import matplotlib.pyplot as plt
import string
def names( infile = 'tiny_names.csv'):
#This takes in the name of the file containing the clean name data and returns a list in the format [year, name, sex, quantity]
def readNames(infile = 'tiny_names.csv'):
#Counts the number of name-year combinations
counter = 0
#Opens the file
file = open(infile, 'r')
#Reads each line into an item on the list
names = [i for i in file]
#Formatting
for i in names:
#increments the counter
counter = counter + 1
index = names.index(i)
#Removes the newline char
names[index] = i.strip('\n')
#splits by the comma
names[index] = names[index].split(',')
#reformats the numbers into ints, makes names all lowercase to make searching easier
names[index] = [ int(names[index][0]), names[index][1].lower(), names[index][2], int(names[index][3])]
#closes the file
file.close()
#returns the names
return(names)
#Takes names as an argument and returns a dictionary with keys of names and values of lists of tuples (year, male births, female births)
def nameIndex(names):
#Initialize the empty dictionary
result = {}
for i in names:
name = i[1]
if name not in result.keys():
#if it's a male, add in the male format
if i[2] == 'M':
result[name] = [(i[0], i[3], 0)]
#otherwise, add in the female format
else:
result[name] = [(i[0], 0, i[3])]
#Checking if there is already a datapoint for that year
elif True in [( i[0] == a[0]) for a in result[name]]:
xx = [( i[0] == a[0]) for a in result[name]]
index = xx.index(True)
#If there is a datum in the male slot, add the new datum to the female slot
if result[name][index][1] == 0:
result[name][index] = (result[name][index][0], i[3], result[name][index][2])
#Otherwise, vice versa
else:
result[name][index][2] == (result[name][index][0], result[name][index][1], i[3])
#if the name exists but the year is unique
else:
#if it is a male, add it in the male format
if i[2] == 'M':
result[name].append((i[0], i[3], 0))
#otherwise add it in the female format
else:
result[name].append((i[0], 0, i[3]))
#Return the results
return(result)
def getBirthsByName (name , gender=None, start=None, end=None, interval=None):
#initialize the return variable
thing = []
#Make the name variable auto match the format of the names
name = name.lower()
#if the name doesn't exist, say so
if name not in nameIndex:
return("Name not in index")
#if there are no time constraints
if not start and not end and not interval:
#cycle through the name Data Points (dp) and addup the numbers for
for dp in nameIndex[name]:
year = dp[0]
#Gender neutral
if not gender:
thing.append((year, dp[1] +dp[2]))
#Males
elif gender.upper() == "M":
thing.append((year, dp[1]))
#Females
elif gender.upper() == "F":
thing.append((year, dp[2]))
#Data validation, gender != m or f
else:
return("You have entered and invalid gender, because we are insensitive people")
else:
#Data Validation, see return comments
if interval and (not start or not end):
return("You must have a start and an end to have an interval")
if not end:
end = 2013 #initializes end if blank
if start:
return("You must have a start to have an end")
if not start:
start = 1880 #initializes start if blank
if not interval:
interval = 1 #initializes interval if blank
#If the input passes all the validation tests, return data
for year in range (start, end, interval):
if year not in yearIndex.keys():
continue
if name not in yearIndex.get(year).keys():
continue
#Assign the tuple to dp
dp = yearIndex.get(year).get(name)
#Gender neutral
if not gender:
thing.append((year, dp[0] +dp[1]))
#Males
elif gender.upper() == "M":
thing.append((year, dp[0]))
#Females
elif gender.upper() == "F":
thing.append((year, dp[1]))
return(thing)
def BBNInput(inp):
split = inp[2:].split()
query = '"' + split[0] + '"'
if (split[1] != None):
query = query + ',"' + split[1] + '"'
if (split[2] != None):
query = query + "," + split[2]
if (split[3] != None):
query = query + "," + split[3]
if (split[4] != None):
query = query + "," + split[4]
return(eval("getBirthsByName(" + query + ")"))
#read the names
print("read the names")
nameList = readNames()
#store the name index
print("make the name index")
nameIndex = nameIndex(nameList)
#initialize the exit bool
exit = False
#Functional loop
while not exit:
queue = []
inp = input('names> ')
if inp == 'x':
exit = True
continue
elif inp[0] == 'c':
data = BBNInput(inp)
total = 0
for dp in data:
total = total + dp[1]
print(total)
elif inp[0] == 'q':
print(BBNInput(inp))
elif inp[0] == 'p':
split = inp[2:].split()
query = '"' + split[0] + '"'
if (split[1] != None):
query = query + ',"' + split[1] + '"'
if (split[2] != None):
query = query + "," + split[2]
if (split[3] != None):
query = query + "," + split[3]
if (split[4] != None):
query = query + "," + split[4]
exec("print(getBirthsByName(" +query + "))")
names()
tiny_names.csv =
1890,Patrick,M,227
1890,Mary,F,12078
1890,Charles,M,4061
1890,Alice,F,2271
1889,Patrick,M,236
1889,Mary,F,11648
1889,Charles,M,4199
1889,Alice,F,2145
1888,Patrick,M,245
1888,Mary,F,11754
1888,Charles,M,4591
1888,Alice,F,2202
1887,Patrick,M,218
1887,Mary,F,9888
1887,Charles,M,4031
1887,Alice,F,1819
1886,Patrick,M,249
1886,Mary,F,9890
1886,Charles,M,4533
1886,Alice,F,1811
1885,Patrick,M,217
1885,Mary,F,9128
1885,Charles,M,4599
1885,Alice,F,1681
1884,Patrick,M,222
1884,Mary,F,9217
1884,Charles,M,4802
1884,Alice,F,1732
1883,Patrick,M,213
1883,Mary,F,8012
1883,Charles,M,4826
1883,Alice,F,1488
1882,Patrick,M,249
1882,Mary,F,8148
1882,Charles,M,5092
1882,Alice,F,1542
1881,Patrick,M,188
1881,Mary,F,6919
1881,Charles,M,4636
1881,Alice,F,1308
1880,Patrick,M,248
1880,Mary,F,7065
1880,Charles,M,5348
1880,Alice,F,1414

Well, now I think there is too much code to obviously see what the problem is. However, you probably don't need to even use eval() at all. The following will likely do what you want:
def BBNInput(inp):
split = inp[2:].split()
return getBirthsByName(*split)
See What does ** (double star) and * (star) do for Python parameters? for further information on what this means.

I fixed it by changing my BBNInput function to a query building function and evaluated (using eval()) on the same level as the def for getBirthsByName. But I think that #GregHewgill has the right of it, makes way more sense. Thanks for your help everyone!

Related

Python - Sort a list contain string and interger

This is my code:
Guess Song V2
import random
import time
def Game():
x = 0
#AUTHENTICATION
Username = input("What is your username?")
#Asking for an input of the password.
Password = str(input("What is the password?"))
#If password is correct then allow user to continue.
if Password == "":
print("User Authenticated")
#If not then tell the user and stop the program
elif Password != "":
print("Password Denied")
exit()
#GAME
#Creating a score variable
score=0
#Reading song names and artist from the file
read = open("Song.txt", "r")
songs = read.readlines()
songlist = []
#Removing the 'new line' code
for i in range(len(songs)):
songlist.append(songs[i].strip('\n'))
while x == 0:
#Randomly choosing a song and artist from the list
choice = random.choice(songlist)
artist, song = choice.split('-')
#Splitting the song into the first letters of each word
songs = song.split()
letters = [word[0] for word in songs]
#Loop for guessing the answer
for x in range(0,2):
print(artist, "".join(letters))
guess = str(input("Guess the song : "))
if guess == song:
if x == 0:
score = score + 3
break
if x == 1:
score = score + 1
break
#Printing score, then waiting to start loop again.
print("Your score is", score)
print("Be ready for the next one!")
score = int(score)
leaderboard = open("Score.txt", "a+")
score = str(score)
leaderboard.write(Username + ' : ' + score + '\n')
leaderboard.close()
leaderboard = open("Score.txt", "r")
#leaderboardlist = leaderboard.readlines()
Scorelist = leaderboard.readlines()
for row in Scorelist:
Username, Score = row.split(' : ')
Score = int(Score)
Score = sorted(Score)
leaderboard.close()
Game()
So this is my code, for the leaderboard feature in this game, I want to make the list (Which contain both string - Username, and Interger - Score) into descending order of score(Interger). It would look something like this:
Before:
Player1 : 34
Player2 : 98
Player3 : 22
After:
Player2 : 98
Player1 : 34
Player3 : 22
Anyone know who to do this?
scores = {}
for row in score_list:
user, score = row.split(':')
scores[user] = int(score)
highest_ranking_users = sorted(scores, key=lambda x: scores[x], reverse=True)
for user in highest_ranking_users:
print(f'{user} : {score[user]}')

python accumulating while loop keeps repeating what did i do wrong?

I can't figure out what I am doing wrong. I have tried using a break, and tried setting what the variable !=, I am doing this on cengage and it is very finnicky.
""" LeftOrRight.py - This program calculates the total number of left-handed and right-handed students in a class. Input: L for left-handed; R for right handed; X to quit. Output: Prints the number of left-handed students and the number of right-handed students."""
rightTotal = 0 # Number of right-handed students.
leftTotal = 0 # Number of left-handed students.
leftOrRight = input("Enter an L if you are left-handed,a R if you are right-handed or X to quit.")
while leftOrRight != "X":
print (leftOrRight)
if leftOrRight == "L":
leftTotal = (leftTotal + 1)
elif leftOrRight == "R":
rightTotal = (rightTotal + 1)
else:
break
print("Number of left-handed students: " + str(leftTotal))
print("Number of right-handed students: " + str(rightTotal))
your input() is outside the while loop, so leftOrRight never changes, never get to X so it will not exit the loop:
leftOrRight = None
while leftOrRight != "X":
leftOrRight = input("Enter an L if you are left-handed,a R if you are right-handed or X to quit.")
print (leftOrRight)
if leftOrRight == "L":
leftTotal = (leftTotal + 1)
elif leftOrRight == "R":
rightTotal = (rightTotal + 1)
else:
break
According to your code you are not changing the value for leftOrRight after entering the loop so the condition for your while loop is never false I would suggest the following edit:
""" LeftOrRight.py - This program calculates the total number of left-handed and right-handed students in a class. Input: L for left-handed; R for right handed; X to quit. Output: Prints the number of left-handed students and the number of right-handed students."""
rightTotal = 0 # Number of right-handed students.
leftTotal = 0 # Number of left-handed students.
leftOrRight = '' #anything random
while leftOrRight != "X":
leftOrRight = input("Enter an L if you are left-handed,a R if you are right-handed or X to quit.")
print (leftOrRight)
if leftOrRight == "L":
leftTotal = (leftTotal + 1)
elif leftOrRight == "R":
rightTotal = (rightTotal + 1)
else:
break
print("Number of left-handed students: " + str(leftTotal))
print("Number of right-handed students: " + str(rightTotal))
so that you get a prompt every time the loop is executed and you can click X to exit
Your program just got the character that had the largest id in the ascii table.
And only doing the first string as the longString = max(n) wasn't even in the while loop.
also max returns the largest value, so in this case it was just converting the text into an ascii number.
instead you should use len(string) which returns the length of the string.
Unlike max() which is used like:
11 == max(11,10,1,2) as 11 is the largest character.
n = (input("Input: ")) #get initial input
longest = 0 #define the varible which we will keep the length of the longest string in
longest_str = "" #define the varible which stores the value of the longest string.
while n: #you don't need that other stuff, while n does the same as while n != ''
n = str(input("Input: ")) #get input
length = len(n) #gets the length of the input
if length > longest: #if the length of our input is larger than the last largest string
longest = length #set the longest length to current string length
longest_str = n #set the longest string to current string
#once the user hits enter (typing "") we exit the while loop, and this code runs afterwards.
print("Longest input was", longest_str, "at", longest, "characters long")
Because there are two specific counts we are accumulating for, and the outlying char is at the end of our input, we can set our while to True to break when we hit a char other that "L" or "R".
leftOrRight = ""
# Write your loop here.
while True:
leftOrRight = input("Enter an L if you are left-handed,a R if you are right-handed or X to quit.")
if leftOrRight == "L":
leftTotal = leftTotal + 1
elif leftOrRight == "R":
rightTotal = rightTotal + 1
else:
break
# Output number of left or right-handed students.
print("Number of left-handed students: " + str(leftTotal))
print("Number of right-handed students: " + str(rightTotal))

Caesar Cipher shift on new lines

I am having a problem with my code trying to do an advanced caesar cipher shift. I changed a certain letter to another, and then added a string to certain parts of a file before encoding, but am having problems doing the shifting now. This is my code:
import string
import sys
count = 1
cont_cipher = "Y"
#User inputs text
while cont_cipher == "Y":
if count == 1:
file = str(input("Enter input file:" ""))
k = str(input("Enter shift amount: "))
purpose = str(input("Encode (E) or Decode (D) ?: "))
#Steps to encode the message, replace words/letter then shift
if purpose == "E":
my_file = open(file, "r")
file_contents = my_file.read()
#change all "e"s to "zw"s
for letter in file_contents:
if letter == "e":
file_contents = file_contents.replace(letter, "zw")
#add "hokie" to beginning, middle, and end of each line
lines = file_contents.split('\n')
def middle_message(lines, position, word_to_insert):
lines = lines[:position] + word_to_insert + lines[position:]
return lines
new_lines = ["hokie" + middle_message(lines[x], len(lines[x])//2, "hokie") + "hokie" for x in range(len(lines))]
#math to do the actual encryption
def caesar(word, shifts):
word_list = list(new_lines)
result = []
s = 0
for c in word_list:
next_ord = ord(c) + s + 2
if next_ord > 122:
next_ord = 97
result.append(chr(next_ord))
s = (s + 1) % shifts
return "".join(result)
if __name__ == "__main__":
print(caesar(my_file, 5))
#close file and add to count
my_file.close()
count = count + 1
The error I am getting is:
TypeError: ord() expected a character, but string of length 58 found
I know that I need to split it into individual characters, but am not sure how to do this. I need to use the updated message and not the original file in this step...

TypeError: must be a unicode character, not str

This code worked with 2.7 but not with 3.5 - I understand that this has something do with being unicode compatible.
This is the code any help would be greatly appreciated
import array
import sys
ConstNoStudents = int(4)
Counter = int(0)
StudentMarkTest1 = array.array("Test 1", range(ConstNoStudents + 1))
StudentMarkTest2 = array.array("Test 2", range(ConstNoStudents + 1))
StudentName = []
StudentGender = []
input_value = raw_input
while Counter <4:
gender_value = int(0)
input_value = raw_input
Counter = Counter+1
StudentName.append (raw_input("Please Enter Student Name "))
print(StudentName)
while gender_value == 0:
gender = raw_input("Please Enter Student Gender ")
if gender == 'm' or gender == 'f' or gender =='M' or gender == 'F':
StudentGender.append(gender)
gender_value = gender_value+1
StudentMarkTest1[Counter] = int(raw_input("Please Enter Mark for Test 1 "))
StudentMarkTest2[Counter] = int(raw_input("Please Enter Mark for Test 2 "))
print (StudentName )
print (StudentGender)
print (StudentMarkTest1 )
print (StudentMarkTest2 )
import array
import sys
ConstNoStudents = int(4)
Counter = int(0)
StudentMarkTest1 = array.array("d", range(ConstNoStudents + 1))
StudentMarkTest2 = array.array("d", range(ConstNoStudents + 1))
StudentName = []
StudentGender = []
while Counter <4:
gender_value = int(0)
Counter = Counter+1
StudentName.append(input("Please Enter Student Name "))
print(StudentName)
while gender_value == 0:
gender = input("Please Enter Student Gender ")
if gender == 'm' or gender == 'f' or gender =='M' or gender == 'F':
StudentGender.append(gender)
gender_value = gender_value+1
StudentMarkTest1[Counter] = int(input("Please Enter Mark for Test 1 "))
StudentMarkTest2[Counter] = int(input("Please Enter Mark for Test 2 "))
print (StudentName)
print (StudentGender)
print (StudentMarkTest1)
print (StudentMarkTest2)
This is the Python3 version of your code, raw_input are now input.
Also, array.array's first parameter needs to be a character defining the data type.

Counting Grades to print

Hopefully this will be very simple all I need help with is getting a count of the letter grades and then printing them along with the list.
Here is my code:
def getScores():
f_obj = open("scores.txt", "r")
data = f_obj.readlines() #read file into a list of record strings
f_obj.close()
return data
def displayData(data):
print("Name Avg Grade")#print headings
for record in data:
name, ex1, ex2, ex3 = record.split()
exam1 = float(ex1)
exam2 = float(ex2)
exam3 = float(ex3)
avg = round(exam1 + exam2 + exam3) / 3
if avg >= 100:
letterGrade = "A"
elif avg >= 89:
letterGrade = "B"
elif avg >= 79:
letterGrade = "C"
elif avg >= 69:
letterGrade = "D"
elif avg >= 59:
letterGrade = "F"
Just above here is where im stuck I cannot figure out how to do a count with the certain letter grades.
print("%-10s %5s %5s" % (name, round(avg, 1), letterGrade))
print()
print(
def addStudent():
name = input("Enter student name: ")
ex1 = int("Enter Exam 1 grade: ")
ex2 = int("Enter Exam 2 grade: ")
ex3 = int("Enter Exam 3 grade: ")
return name + "\t" + ex1 + "\t" + ex2 + "\t" + ex3
def storeData(data):
f_obj = open("scores.txt", "w")
f_obj.writelines(data)
f_obj.close()
def main():
scoreData = getScores() # read data file into a list
while True:
print("""
Program Options
1.) Display Students.
2.) Add a new student:
3.) Exit Program """)
option = input("Enter option 1, 2, or 3: ")
if option == "1":
displayData(scoreData)
elif option == "2":
scoreData.append(addItem()) # add record string to our list
elif option == "3":
storeData(scoreData)
print("Good bye.")
break
else:
print("Not a valid entry. Please enter 1, 2, or 3.")
main() # start the program
Hint: you already know how to determine if a grade is an A, B, C, etc. So all you need to do is increment a counter at the same time.
For example, you'd add in something like this to count the number of A grades:
if avg >= 100:
letterGrade = "A"
numAs += 1
Then do the same thing for each other grade type. Since this appears to be homework, I'll let you figure out how to do all this. Most importantly, even though Python isn't strict about this, think about the correct place to declare the counter variables.
Once you've got that working, here's an "extra credit" assignment: see if you can do all that using just a single array.

Resources