Python 3.x: User Input to Call and Execute a Function - python

There are many questions similar to this out there but none of the answers solved my issue.
I have defined several functions that parse large data sets. First I call the data, then I organize the data (represented as rows and columns in a .txt) into lists which I will index for individual data entries. After that I establish my functions that will work through the lists one at a time. The code looks like:
f = open(fn)
for line in iter(f):
entries = [i for i in line.split() if i]
def function_one():
if entries[0] == 150:
# do something
def function_two():
if entries[1] == 120:
# do something else
def function_three():
if len(entries) > 10:
# do something else
etc. etc.
I have attempted to prompt the user asking what function they would like to execute as each function returns different things about the data set. My attempt is as follows:
f_call = input('Enter Function Name: ')
if f_call in locals().keys() and callable(locals()['f_call']):
locals()['f_call']()
else:
print('Function Does Not Exist')
When I run the script, I am prompted to 'Enter Function Name:' and if I type in 'function_one' and return, it prints 'Function Does Not Exist'. I want to see that, if entered correctly, the script will execute only the function that the user entered. If the user input is correct, the function should run and print the parsed data.
I have also attempted using a dict to store the functions but I have not had success.
Any help would be greatly appreciated.

Based on your comments, I think you're trying to achieve something like this:
def function_one(data):
if data[0] == 150:
pass # do something
def function_two(data):
if data[1] == 120:
pass # do something else
def function_three(data):
if len(data) > 10:
pass # do something entirely different
This defines your functions that accept arguments so you can re-use them later on. Then you'd like to ask the user which function to use when processing the data, so:
while True: # loop while we don't get a valid input
user_function = input('Enter a function name to use: ') # ask the user for input
if user_function in locals() and callable(locals()[user_function]): # if it exists...
user_function = locals()[user_function] # store a pointer to the function
break # break out of the while loop since we have our valid input
else:
print('Invalid function name, try again...')
Finally, you can load your file, read it line by line, split it up and process it by the function decided by the user:
with open(file_name, "r") as f:
for line in f:
entries = line.split() # no need to check for empty elements
user_function(entries) # call the user selected function and pass `entries` to it
Of course, you can do further processing afterwards.
UPDATE - Here's a simple test for the above code, given the file test_file.txt containing:
tokenized line 1
tokenized line 2
tokenized line 3
and file_name = "test_file.txt" defined in the file, while the functions are defined as:
def function_one(data):
print("function_one called: {}".format(data))
def function_two(data):
print("function_two called: {}".format(data))
def function_three(data):
print("function_three called: {}".format(data))
If you execute the code this is the output/trace:
Enter a function name to use: bad_name_on_purpose
Invalid function name, try again...
Enter a function name to use: function_two
function_two called: ['tokenized', 'line', '1']
function_two called: ['tokenized', 'line', '2']
function_two called: ['tokenized', 'line', '3']

to make your code work, just keep the variable f_call without '' when you call it
f_call = input('Enter Function Name: ')
if f_call in locals().keys() and callable(locals()[f_call]):
locals()[f_call]()
else:
print('Function Does Not Exist')

It may not be the most efficient way to fix it, but you could use something like this:
f_call = raw_input('Enter Function Name: ')
if f_call == "function_one":
function_one()
if f_call == "function_two":
function_two()
if f_call == "function_three":
function_three()
else:
print('Function Does Not Exist')

Related

Accessing a variable after being appended in file a.py from a function in file b.py

I have a problem trying to access a variable from file a.py from a function in file b.py. I tried looking around the internet and could not find anything, or I don't know exactly how to look for what I need. I also tried to make another file and update the variable in file c.py, but file b.py still see's the first initialization of the variable. I tried to update the variable in file a.py and afterwards import a.py in the function in b.py.
File a.py
var = []
def run():
a.welcome()
while True:
menu = a.menu()
if menu == 1:
def retrieve_path(source_path):
"""The function takes 1 parameter and checks if the file name exist as well as the file path
Adds the csv data to a variable
source_path (str): Path against whom to check for validity
"""
if not source_path:
print("Invalid file name, Please try again\n")
return
else:
import os
isFile = os.path.isfile(source_path)
if not isFile:
print("Invalid file path\n")
return
else:
with open(source_path, "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for line in csv_reader:
line = list(line)
var.append(line)
if __name__ == "__main__":
run()
file b.py
I tried like this but I get the first initialization of the variable var = []
I first updated var from file a.py and afterwards, I tried to use the function below inside file b.py but still the same result.
from a import var
from a import *
import a
def a_function():
from a import var
from a import *
import a
print(var)
print(a.var)
This prints the first initialization of var which = [] not after it was appended.
If I print var from a, from inside the function it prints it updated.
If I print var from a, from outside the function it prints it updated.
What I don’t understand is, why after updating it, and importing it into b, I still get the first initialization. Debugger didn’t help as well.
I can work around it by adding the function retrieve_path inside b.py and then appending the data in another variable inside file b.py but I would like to know why its not importing var updated with the data.
File b.py
var2 = []
def retrieve_path(source_path):
"""The function takes 1 parameter and checks if the file name exist as well as the file path
Adds the csv data to a variable
source_path (str): Path against whom to check for validity
"""
if not source_path:
print("Invalid file name, Please try again\n")
return
else:
import os
isFile = os.path.isfile(source_path)
if not isFile:
print("Invalid file path\n")
return
else:
with open(source_path, "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for line in csv_reader:
line = list(line)
var.append(line)
var2.append(line)
The reason I didn't use Class if that was one of the solutions, is because I haven't learned that much about Classes and don't know how to use them properly for the time being.
I hope I was quite explicit and you understand my dilemma. Also, have in mind I just started learning Python, so a newbi explanation and solution are more than welcomed.
The correct way is to call the run function before accessing var. Either
import a
a.run
print(a.var)
or:
from a import var, run
run
print(var)
The import statement only runs the content of the module, not the functions declared in it.
The idiomatic way of running a script is indeed what you have in a.py:
if __name__ == "__main__":
run()
And the run function will be called if you use the file like a script with python a.py, because a file that is started directly by the interpretor will be named __main__. But when it is imported, it is named according to the file name. So here it would be a and not main. Said differently, run is never called when a.py is imported.
One possibility would be to end a.py with an unconditional call of run:
...
line = list(line)
var.append(line)
run()
It should be harmless because Python keeps track of the already imported module, and run should be called only once even if the module was imported from multiple places. Yet it would be an anti-pattern, because by convention import should have as few side effects as possible, while run seems to do plenty of actions.
Ok, this is just a part of the project which was for the school, which I finished, but I wanted to make this part with records a little bit different than I've done for the grade. If some function dont make sense, its because the project it is not finished. My only concerned is towards records variable.
main.py
import tui, csv
records = []
def run():
tui.welcome()
while True:
menu = tui.menu()
if menu == 1:
def retrieve_path(source_path):
"""The function takes 1 parameter and checks if the file name exist as well as the file path
Adds the csv data to a variable
source_path (str): Path against whom to check for validity
"""
if not source_path:
print("Invalid file name, Please try again\n")
return
else:
import os
isFile = os.path.isfile(source_path)
if not isFile:
print("Invalid file path\n")
return
else:
with open(source_path, "r") as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for line in csv_reader:
line = list(line)
records.append(line)
tui.started("Data Loading")
retrieve_path(tui.source_data_path())
tui.completed("Data Loading")
if menu == 2:
tui.started("Retrieving data")
process_menu = tui.process_type()
tui.completed("Retrieving data")
if process_menu == 1:
tui.started("Retrieving entity name")
tui.entity_name()
tui.completed("Retrieving entity name")
if process_menu == 2:
tui.started("Retrieving entity details")
entity, cols = tui.entity_details()
tui.list_entity(entity, cols)
tui.completed("Retrieving entity details")
if menu == 3:
print(tui.main_records)
if menu == 4:
break
if __name__ == "__main__":
run()
Second file is:
tui.py
def welcome():
message = "System Management"
print("*" * len(message))
print(message)
print("*" * len(message))
def menu():
main_menu = "-"
while main_menu != "0":
if main_menu == "-":
print('Main Menu:'
'\n1. Load Data'
'\n2. Process Data'
'\n3. Visualise Data'
'\n4. Save Data'
'\n0. Exit')
elif main_menu in "1234":
return int(main_menu)
elif main_menu not in "1234":
error(main_menu)
return None
else:
print('Main Menu:'
'\n1. Load Data'
'\n2. Process Data'
'\n3. Visualise Data'
'\n4. Save Data'
'\n0. Exit')
main_menu = input()
def started(operation):
print("{} has started.\n".format(operation))
def completed(operation):
print("{} has completed.\n".format(operation))
def error(error_msg):
print("Error! {} is not a valid option.".format(error_msg))
def source_data_path():
print("Please enter the path to the source data file:")
source_path = input()
if ".csv" not in source_path:
return None
else:
return source_path
def process_type():
process_menu = "-"
while process_menu != "0":
if process_menu == "-":
print('Process Menu:'
'\n1. Retrieve entity'
'\n2. Retrieve entity details'
'\n3. Categorise entities by type'
'\n4. Categorise entities by gravity'
'\n5. Summarise entities by orbit'
'\n6. Return to Main Menu')
elif process_menu == "6":
menu()
return None
elif process_menu in "12345":
return int(process_menu)
elif process_menu not in "12345":
error(process_menu)
return None
else:
print('Process Menu:'
'\n1. Retrieve entity'
'\n2. Retrieve entity details'
'\n3. Categorise entities by type'
'\n4. Categorise entities by gravity'
'\n5. Summarise entities by orbit'
'\n6. Return to Main Menu')
process_menu = input()
def entity_name():
entity = input("Please enter the name of an entity: ")
return entity
def entity_details():
entity = input("Please enter the name of an entity: ")
indexes = input("Please enter the indexes number (e.g. 0,1,5,7):\n")
return entity, list(indexes)
Please have
First time I did the project I added def retrieve_path(source_path): to tui.py and it worked fine.
What I don't really understand is why is the variable records being appended to, I can print it from within run and outside of run function, but in tui.py i get only records = [] and how to solve this without creating the function retrieve_path in tui.py
This is what it was asked of us at the time being and it was not my personal choice to do it like this.
I am sorry for not pasting everything here and mistyping some parts like == _ main _ .

How to write a function that takes in the name of a file as the argument in Python?

I need to create a function return_exactly_one(file_name) that takes in the name of a text file as the argument, opens the text file, and returns a list that only contains words that occurred exactly once in the text file. My file is test.txt, but I have trouble about the argument of the function. I'm not allowed to take test.txt as the argument, because it's an invalid variable. And when I call the function, what should I put into the parenthesis? How to solve it? Thanks. My code is as follows.
import string
def return_exactly_one(test):
test = open("test.txt", "r")
text = test.read()
test.close()
for e in string.punctuation:
if e in text:
text = text.replace(e, "")
text_list = text.split()
word_count_dict = {}
for word in text_list:
if word in word_count_dict:
word_count_dict[word] +=1
else:
word_count_dict[word] = 1
once_list = []
for key, val in word_count_dict.items():
if val == 1:
once_list.append(key)
return once_list
print(__name__)
if __name__ == "__main__":
print("A list that only contains items that occurred exactly once in the text file is:\n{}.".format(return_exactly_one(test)))
Your function should take a string filename as a parameter, like this:
def return_exactly_one(filename):
test = open(filename, "r")
...
and then you would call the function like:
return_exactly_one("test.txt")
I'm not sure what's preventing you from doing that. You need only store the filename as a string and pass the string to the function. So for example, you could take the filename as input like so:
file_name = input("Enter the name of the file:")
And then call the function with the file name like so:
return_exactly_one(file_name)
Also, inside the function you'd open it this way:
test = open(file_name, "r")
# Notice, no quotes, it's a variable here, not a string

Call to a variable that is inside another function

def HOME():
""" The first screen
"""
print ('Welcome to my program!')
input_grocery_list = input('Hello, please enter here a list of groceries: ')
def input_to_list():
""" This f takes the input
and put it inside a list
without the: ','
and print the list
"""
new_grocery_list = []
separator = ", "
while ',' in input_grocery_list:
d = input_grocery_list.index(',')
y = input_grocery_list[:d]
new_grocery_list.append(y)
input_grocery_list = input_grocery_list[(d+1):]
if ',' not in input_grocery_list:
new_grocery_list.append(input_grocery_list)
print(separator.join(new_grocery_list))
def the_groceries_list():
""" Do somthing to the first input
accord to the next choice
"""
print("You can chose a number betwen 1 - 9 n/ and we do the rest..")
grocery_list = input('please enter here your choice : ')
if grocery_list == '1':
input_to_list(input_grocery_list)
if len(input_grocery_list) != 0:
the_groceries_list()
HOME()
The error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 37, in HOME
File "<stdin>", line 34, in the_groceries_list
TypeError: input_to_list() takes 0 positional arguments but 1 was given
My problem is probably in the second function called "input_to_list ()"
  While I am trying to read / change the "input_grocery_list" variable that is inside the first function (HOME)
It does not recognize him.
I tried to fix it using global or self but I probably don't really know where exactly to put them because in the meantime it didn't work for me.
Anyone know how I can fix this?
As I can see, you try to have a main function, but you should use a class instead of a function, so more like this.
class Home():
def __init__(self):
"""
define your class wide variables here as following
"""
# example
# self.your_name = 'hello'
# to access it in an function IN this class, type: self.your_name
pass
def get_items(self):
print('Welcome to my program!')
input_grocery_list = input('Hello, please enter here a list of groceries (sep with comma): ')
self.input_to_list(input_grocery_list)
# you forgot this
# ||
# \/
def input_to_list(self, grocery_list: str):
""" This f takes the input
and put it inside a list
without the: ','
and print the list
"""
new_grocery_list = grocery_list.split(',')
# to print as list
print(new_grocery_list)
# to print every item in list
for item in new_grocery_list:
print(item)
# print('List End') # if you want to
# I don't really know what that is supposed to do, but whatever it is it wont
"""
def the_groceries_list(self):
# Do somthing to the first input
# accord to the next choice
print("You can chose a number betwen 1 - 9 n/ and we do the rest..")
grocery_list = input('please enter here your choice : ')
if grocery_list == '1':
input_to_list(input_grocery_list)
if len(input_grocery_list) != 0:
the_groceries_list()
"""
# to use this class and it's functions first create an object
home = Home()
# than call a function
home.get_items()
I wont go into details of Classes and Object but here is a link for you.
Read this, it should explain the basics pretty good.
You need to change definition of your nested function so it can take args:
def input_to_list(input_grocery_list):

Calling Functions in Main Function

I've written a program and want to call the functions in the main. However, I've been receiving a SyntaxError. I'm not sure what I'm doing wrong. Here is my code, I've tried a few things but the main function won't call the rest of the functions.
class Matrix(object):
def open_file():
'''Opens the file if it exists, otherwise prints out error message'''
Done = False
while not Done:
try:
File = input("Enter a filename: ").lower() #Asks user for a file to input
Open_File = open(File, "r") #Open the file if it exists and reads it
Info = Open_File.readlines()[1:]
Open_File.close() #Close the file
Done = True #Exits the while loop
except FileNotFoundError:
print("Sorry that file doesn't exist!") #prints out error message if file doesn't exist
return Info #Info is the file_pointer(fp)
def __init__(self): # This completed method is given
'''Create and initialize your class attributes.'''
self._matrix = {} #Intialize the matrix
self._rooms = 0 #Set the rooms equal to zero
def read_file(self, Info): #Info is equvalient to the file pointer or fp
'''Build an adjacency matrix that you read from a file fp.'''
self._rooms = Info.readline()
self._rooms = int(self._rooms)
for line in Info:
a, b = map(int, line.split())
self._matrix.setdefault(a, set()).add(b)
self._matrix.setdefault(b, set()).add(a)
return self._rooms and self._matrix
def __str__(self):
'''Return the adjacency matrix as a string.'''
s = str(self._matrix)
return s #__str__ always returns a string
def main(self):
matrix = Matrix()
info = matrix.open_file()
matrix.read_file(info)
s = str(matrix)
print(s)
if __name__ == '__main__':
m = Matrix()
m.main()
A few things:
it's self.read_file, not just read_file. It's an instance method so you need to use self.
Same for __init__(self), you need to call self.__init__. Although typically you don't do this manually. You would "instantiate" the class via Matrix().
You can't assign to a function call, so open_file() = Info simply doesn't make sense. Perhaps you mean info = open_file().
It looks like you're a little confused about how to lay out your class. Try leaving main outside of the class, like this (untested):
def main:
matrix = Matrix()
info = matrix.open_file()
matrix.read_file(info)
s = str(matrix)
print(s)
You will also need to dedent if __name__ == '__main__' to the global scope.
Ideally you may want to write something like below. Also, your open_file() has to be rewritten.
class Matrix(object):
def open_file(self):
File = input("Enter a filename: ").lower() #Asks user for a file to input
fp = open(File, "r")
return fp
#### Your matrix class code goes here
def main():
myMatrix = Matrix()
fp = myMatrix.open_file()
ret = myMatrix.read_file(fp)
print(myMatrix)
if __name__ == "__main__":
main()
There is an error in your program's entry. ' if name == 'main':'shouldn't be included in a Class. It should be global. And another, you want to call a member function of Matrix, but where is the object of Matrix. The code below is correct:
Class Matrix(object):
#################
your codes
#################
if __name__ == '__main__':
m = Matrix()
m.main()
the way this is posted
if __name__ == "__main__":
main()
is going to be executed when the class is defined -- not when the program is run. As written, the class won't have been instantiated so there's no Matrix object on which you can call main().
You'll need to move the call out one indent, so it is aligned with the class definition, and then create an object before calling its main():
if __name__ == "__main__":
instance = Matrix()
instance.main()
You've also got the assignments backwards in main(). It should read more like this:
info = open_file()
self.read_file(Info)
s = __str__(self)
print(s)
the open_file() method also has some issues. You want to create Info outside the scope of your loop so you know you've got it to return. Your comment indicates the Info is supposed to be the file pointer -- but it's not, as you wrote it. Open_File is the file pointer, and Info is the content of the file (at least, everything but the first line). Unless you're expecting a huge amount of data, it's probably easier to pass the contents -- or to combine open_file and read_file into the same function.
You also want to use the usual python pattern for opening and closing the files the with context manager - that will close your file for you.
Heres a quick and dirty version of Open_file and Read_file in one package.
def read_file(self):
#get the filename first
filename = None
while not filename:
user_fn = input("Enter a filename: ").lower()
if os.path.exists(user_fn):
filename = user_fn
else:
print ("Sorry that file doesn't exist!")
# 'with' will automatically close the file for you
with open(filename, 'rt') as filepointer:
# file objects are iterable:
for line in filepointer:
a, b = map(int, line.split())
self._matrix.setdefault(a, set()).add(b)
self._matrix.setdefault(b, set()).add(a)
I'm not clear what self._matrix.setdefault(a, set()).add(b) is supposed to be doing for you here, but in syntactic terms you can simply the structure to "get the filename, open with with, iterate over it"

How to take arbitrary variables loaded by exec, and use them in a function

I'm looking to write up a basic Bioinformatics course on Codeacademy. They have a nice interface for writing up a course, but it's a bit slow for testing, as one must save, then preview, then run.
So I'm looking to write up a little testing environment that mimics their one. How it appears to work is that the user-input code is read in to a function as a string, all str instances in the code are converted to unicode (I've just used regex for this) and then the code is executed with exec.
The tricky part seems to be when I want to incorporate the Submission Test.
Submission Tests need to return True, False, or a str, and are written as the body of a function. So for example:
A simplified version of what I'm looking to do:
# The submission test must be a function.
def test_code(code, CC, error):
# Use information from errors in student code
if error:
return "Yada yada %s" %error
# Use information in the raw student code
if len(code.split("\n")) is not 2:
return "This should be accomplished in 2 lines"
# Have direct access to variables from the student code
# I'd like to avoid params['y'] if possible.
try:
y
except NameError:
return "Please use the variable y"
if y is not 8:
return "Wrong! Check stuff"
# Use information from print output
if str(y) not in CC:
return "Remember to print your variable!"
return True
# Read in student code
student_code = """y = 8
print y
potato"""
# Catch print output
CC = StringIO.StringIO()
sys.stdout = CC
# Execute student code and catch errors
try:
exec student_code
except Exception as e:
error = e
# Start outputting to the terminal again
sys.stdout = sys.__stdout__
# Run the submission test
submission_test = test_code(student_code, CC.split("\n"), error)
# Output the result of the submission test
if submission_test is True:
print("Well done!")
elif submission_test is False:
print("Oops! You failed... Try again!")
else:
print(submission_test)
However, I can't seem to get the variables from exec code to pass through to the submission test function (test_code in this case).
I could just execute the code in the Submission Test, but I'd like to avoid that if possible, otherwise it will have to be added to each test, which just seems unpythonic!
Any help would be greatly appreciated :)
If you exec mystr in somedict, then somedict has a reference to every variable assigned during the execution of mystr as Python code. In addition, you can pass variables in this way, too.
>>> d = {'y': 3}
>>> exec "x = y" in d
>>> d['x']
3
You need to pass the dictionary you got from running the user code in, so that the submission check code can verify the values in it are appropriate.
It sounds like you want the code and the test to run in the same environment. Both are being submitted as strings, so perhaps the easiest way is to concatenate both and run exec on the combined string:
from __future__ import unicode_literals
def wrap_body(body):
indent = ' '*4
return 'def test():\n' + indent + body.replace('\n','\n'+indent)
code = '''
bool_1 = True
bool_2 = False
str_1 = 'Hello there!'
str_2 = "I hope you've noticed the apostrophe ;)"
'''
code_test = '''
try:
bool_1, bool_2, str_1, str_2
except NameError:
return "Please do not alter the variable names!"
if (bool_1 == bool_2 or str_1 == str_2):
return "Please ensure that all of your variables are different " \
"from one another"
if type(bool_1) != bool: return "bool_1 is incorrect"
if type(bool_2) != bool: return "bool_2 is incorrect"
if type(str_1) != unicode: return "str_1 is incorrect"
if type(str_2) != unicode: return "str_2 is incorrect"
return True
'''
code_test = wrap_body(code_test)
template = code + code_test
namespace = {}
try:
exec template in namespace
print(namespace['test']())
except Exception as err:
print(err)
Okay, my colleague figured this one out.
It uses an element of Devin Jeanpierre's answer.
We use the exec code in dictionary method, then pass the dictionary into the checking function, then, within the checking function we unpack the dictionary into the globals().
# The submission test must be a function.
def test_code(code, CC, error, code_vars):
# unpack the student code namespace into the globals()
globs = globals()
for var, val in code_vars.items():
globs[var] = val
# Use information from errors in student code
if error:
return "Yada yada %s" %error
# Use information in the raw student code
if len(code.split("\n")) is not 2:
return "This should be accomplished in 2 lines"
# Have direct access to variables from the student code
# I'd like to avoid params['y'] if possible.
try:
y
except NameError:
return "Please use the variable y"
if y is not 8:
return "Wrong! Check stuff"
# Use information from print output
if str(y) not in CC:
return "Remember to print your variable!"
return True
# Read in student code
student_code = """y = 8
print y
potato"""
# Catch print output
CC = StringIO.StringIO()
sys.stdout = CC
# create the namespace for the student code
code_vars = {}
# Execute student code and catch errors
try:
# execute the student code in the created namespace
exec student_code in code_vars
except Exception as e:
error = e
# Start outputting to the terminal again
sys.stdout = sys.__stdout__
# Run the submission test
submission_test = test_code(student_code, CC.split("\n"), error, code_vars)
# Output the result of the submission test
if submission_test is True:
print("Well done!")
elif submission_test is False:
print("Oops! You failed... Try again!")
else:
print(submission_test)

Categories

Resources